AV-Portal 3.23.3 (4dfb8a34932102951b25870966c61d06d6b97156)

The Case for interface

Video in TIB AV-Portal: The Case for interface

Formal Metadata

The Case for interface
When and how to use empty interface
Title of Series
CC Attribution 2.0 Belgium:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Release Date

Content Metadata

Subject Area
Slide rule Standard deviation Personal digital assistant Multiplication sign Interface (computing) Bit
Interface (computing) Bit
Sensitivity analysis Context awareness Presentation of a group Metric system Java applet Perspective (visual) Side channel attack Mechanism design Core dump Finite-state machine Information security Descriptive statistics Physical system Constraint (mathematics) Mapping Software developer Bit Instance (computer science) Windows Registry Virtual machine Electronic signature Arithmetic mean Message passing Process (computing) Chain Pattern language Quicksort Figurate number Point (geometry) Random number Inheritance (object-oriented programming) Rule of inference Latent heat Goodness of fit Cache (computing) Boundary value problem Representation (politics) Authentication Standard deviation Key (cryptography) Information Interface (computing) Code Generic programming Basis <Mathematik> System call Word Loop (music) Error message Algebraic closure Web-Designer Personal digital assistant String (computer science) Mixed reality Finite-state machine Integer Library (computing) Interior (topology) Code State of matter Multiplication sign Insertion loss Parameter (computer programming) Mereology Formal language Subset Facebook Software framework Library (computing) Injektivität Email Reflection (mathematics) Price index Flow separation Exergie Connected space Mechanism design Type theory Proof theory Normal (geometry) Right angle Authorization Metric system Middleware Dataflow Implementation Functional (mathematics) Game controller Server (computing) Observational study Codierung <Programmierung> Field (computer science) Revision control String (computer science) Integer Software testing Context awareness Dependent and independent variables Multiplication Validity (statistics) Military base Database Software maintenance Leak Subject indexing Cache (computing) Data flow diagram Password Boundary value problem Communications protocol
Point (geometry) Modal logic Interface (computing) Software developer Reflection (mathematics) Parameter (computer programming) Perspective (visual) Type theory Error message Computer configuration String (computer science) Integer Quicksort
Service (economics) Collaborationism
so yeah I'm Sam white ed I'm a sometimes
work for the XMPP standards Foundation I'm not sure why that's on there I think I copy pasted from some old slides but I'm also currently employed by CloudFlare so obligatory we're hiring animate occasional go contributor and I'm gonna talk a bit about the empty interface I called the talk the case for empty interface but I'm not really arguing for it I'm just kind of trying to to figure out when is a good time to use the empty interface and when is it a
problem so I suspect everyone in this room I don't I suspect I don't have to give an introduction to empty interface for this crowd or why it can often be a problem it's one of those feature of go that ends up giving you a lot of interesting problems but there's also very useful and I will start with some assumptions that I think will if you
don't know what empty interface is they might explain a little bit about it and if you do these are just some
assumptions you'll need to know or need to agree with potentially if you're going to agree with this presentation so the first one is in go interfaces should describe behavior not data I think that's one of the go proverbs and it's kind of part of the basis for this talk also the empty interface is easy to abuse and thus is abused this is just something if you don't agree with this you know we can argue afterwards but it's that's sort of the fundamental underlying assumption for this talk also any time I say empty interface you should hear optional dynamic typing and if you don't know what empty interface is that's the most succinct description I can give you and if you can describe your behavior with a more specific type you should I think this is another one of the go proverbs and finally possibly the most controversial heavy use of reflection leads to difficult to maintain code and if you're a ruby developer and disagree with this then go attempt to modify one of the encoding slash json or xml packages and then get back to me afterwards and those are sort of the things you need to understand going in or maybe not agree with but it would be helpful so let's start with the encoding packages I'll be using an example from encoding XML but it's exactly the same in JSON pick your pick your poison we're gonna look at the Marshall API now from the users perspective Marshall is a elegant maybe even beautiful API it's encoded right in the right in the function signature I give it some arbitrary data empty interface and I get some arbitrary representation out and that's great because the producer of the value in the MT interface the user of the library doesn't really have to care about the data they just put some data in and get some data out it's very very succinct very nice to use works very well there are other methods if you need more control but when you start digging and this is all this empty interface says nothing is one of Rob pikes famous at go proverbs and that's really all you need in this specific API nothing you don't need to know anything about the value of V but from the package developer's perspective this leads to from the XML package developers perspective this leads to a lot of problems it's obvious what to do with V if V is a type from the standard library if it's an int we make up some representation for an int and we can do a nice simple type switch that decides is this an int is this a string is this some other type if it's something defined in the XML package like the XML Marshall our interface it also has a predefined behavior the XML package can know if it's next ml Marshall ER call it's Marshall XML function but as soon as we start getting into user-defined types and more complex types like some arbitrary struct that is not defined in the XML package it becomes really difficult for the XML package to know what to do with that data on this struct the XML package knows nothing about the any of the fields it doesn't know about name it doesn't know about tags it doesn't know about the layout of the struct now we could limit the usefulness of the XML package and not not support user-defined types but that's not going to be very useful people aren't going to use our package so the way that information has to be gathered is using reflection and that leads to effectively two separate code bases half of the package is reflection based half of it is normal idiomatic go and it's very hard to reconcile these sort of two distinct code bases hard to get data between them hard to read the reflection and process the reflection based parts of the package if you're trying to work on it so it's great from the users perspective not so great from the package maintainer perspective this use of empty interface so when the producer of some data the user of the package in this case does not care about the type but the consumer does the XML package which is consuming that empty interface the library becomes difficult to maintain reformulated that gives us our sort of first rule for using empty interface the producer of the empty interface value in the empty interface must also be the consumer of that value so let's talk about another package context and context is actually going to have problems because of this rule and we'll have to modify it a bit to make this make this work so if you haven't used context before this is sort of the basic trimmed-down version most of these examples will be a little trim down trim down version of the API that we care about context is effectively an associative array or a map you have a key and a value and you can index things by that key and get things out the implementation doesn't really matter but in context the key and the value are empty interfaces and the consumer is also the producer like that last rule most of the time when you create a context you are for instance doing it for some HTTP middleware and your package has a loop that's not right your package has I say get session ID from context and insert session ID the Erb new context with session ID function so you are both creating and consuming from within that package the empty interface value and this makes the context package a study in simplicity if you've never looked at the code I really recommend it it's it's very simple very elegant package but it has some other problems so let's look at a quick the documentation for context package context defines the context type which carries deadlines cancellation signals and other requests scoped values across API boundaries and between processes requests scoped values is the kind of key word here what does that mean it's sort of a we don't really know this is API as duck or documentation as API because this wasn't something that was encoded in the API we have for context nothing in here gives you any indication of what a request scope value is or how context should be used so these request scope values I think the original idea was to have things like session ID request ID maybe a trace ID if you're using some sort of tracing basically anything that's a simple value that ends in ID maybe that last parts a little bit of a stretch but very simple values unfortunately I suspect we've all seen context abused to do things like this a lot of times I find in new Java developers for instance that are coming in to go who are other languages where you're used to a pattern like this Discover goes dependency injection package and love to abuse context to put in database connections and metrics and various loggers don't do this it's terrible it leads to a maintainability nightmare because this is effectively an undocumented side channel API I suspect we've all run into this at some point where you say well how am I getting my database connection in my middleware and someone says if you're a web developer and someone says oh well that's just in a context based on a key in some package somewhere and none of that was in the function signature and none of that was in the API and you had to kind of dig through and find it and then you're trying to type assert on a thing in a context and figure out if it works but maybe it doesn't because someone's inserted the wrong middleware in the chain and it it just becomes a nightmare and it's very hard to to use so this is
a sort of more specific example of one of those this is the common no really don't do this with context thing because you see there's a the kind of basic middleware pattern people use when they're abusing context this way is you get the context you insert a value with int or create a new context with that value and then you create a new request with that new context and pass it on through your middleware chain none of this really is tied to the request specifically or none of this guarantees that the value you're using is really request scoped so this kind of leads us to our second rule the way the reason this is abusable as a side channel api is because this context leaks between packages or this empty interface leaks between packages so empty interface should not cross package boundaries otherwise it's able to be used as a side channel api and kind of slip smuggle data through into packages where it's not supposed to be finally we'll take a look at a third package and I couldn't find a good example of this in the standard library and I'm sure one exists and if I if there's a much better example I hope someone will tell me afterwards so I'm going to use an example from one of my packages Sasol is a authentication framework that's widely used you probably use it every time you log in to check your email with smtp or you probably use whatsapp or facebook chat or something i don't actually know what they use but it's just a widely used potentially multi round-trip authentication framework so i have a little go library that uses it and the api looks something like this we have a mechanism which are things like plain username and password authentication oath to various kind of authentication systems a negotiator which is a state machine that actually handles the authentication flow make sure that replay attacks aren't possible make sure that that general security constraints are enforced and that has a function the the user of the package calls to advance the state machine and accept challenges and returns responses and you can serialized that and your whatever your chat protocol or your email or whatever the protocol is and send them over the wire so as you can see the mechanism API takes and returns an empty interface and this I think is actually a pretty good use of interface because this mechanism might be defined by a user in their own package but the way it works is every single time the negotiator step method is called we're moving we've gotten a new authentication request or something over the wire and we are advancing the state machine and trying to do some sort of authentication it calls this mechanism its work calls this mechanisms next function that's the user-defined whatever Oh off to specific what we need to do thing that returns some data since this a so might be multi-step in a future step you might need a value from an earlier step so for instance in scram which is just is a password based authentication where you never send the password you do a proof of possession one of the ways the server makes sure it's still talking to the same person is it returns a signed version of the very first message that was sent which is also something I think TLS does and so you you have this data you might need in another step unfortunately for reasons that don't really matter here mechanisms have to remain stateless or don't have to but it's because this is a thing users are writing and is authentication based it's it's important to keep them stateless because keeping things stateless makes them simpler and auth code is notoriously difficult to write and difficult to get correct to begin with and as security sensitive so we want to make things as simple as possible but there is this state that needs to be stored somewhere so since the negotiator the state machine is already stateful for obvious reasons it's called a state machine we can return that state that needs to be stored the negotiator will store it for us and then when it calls next again in future steps it will pass that back in as the data parameter that all sounds very complicated and it kind of is I wish I tried to draw a flow diagram but for some reason I couldn't get bucks drawing characters to show up our work at all have no idea why and I tried to do a JPEG and it was awful and I kind of gave up after a while but the idea is data is returned from cache and then the next step past into passed back in as the data parameter and this keeps things very simple it means that could the producer is always the consumer this next function always puts a value into cash and is always getting it back in data and that means that in practice the next functions are generally always structured like this when people write these mechanisms you end up with a something like a step that checks the states this API is not what it looks like in the actual package that's sort of simplified but so it might check step one are we in step one step two step three with a switch or an F or something put some data in this case a randomly selected integer in to return it for use in a future step and then because it returned it it can always assert on the type of that data and it knows that it will never be mistaken it's very easy to test and it's very simple and easy to read I think this is a slightly better use of empty interface and it follows these two rules we've mentioned before and this is the the point in the talk I think yep where I have a bit of a confession to make I've been deliberately wasting your time both of these rules actually kind of simplified down into a much simpler rule that encompasses both of them and it took me a while to realize this is which is why I bothered with the rest of the talk because hopefully it kind of gave you a few examples first that will make this make more sense my real rule for using empty interface is you must always be able to type a cert on the value in the empty interface and if you can't do that it's going to lead to problems so empty interface gives you it's not that it's useless you it's easy to say well if I can type a cert why don't I just return an int but I lie in a lot of cases you do need arbitrary data in some languages you would use generics for this and others there are other mechanisms and go that's sort of a mix of empty interface and closures but if you are using the empty interface and you have some arbitrary data that you need to return it needs to be no arbitrary data you must always be able to type assert on that data and that will main make sure that you don't run into maintainability problems later and I think that's sort of the the core rule when using empty interface that needs to be followed and there's a lot of other examples if you go dig through the standard library but these are my kind of three rules for using empty interface I'm gonna end really early that's really it so if anybody has any questions I'd be happy to take them in the back so defining a method I'll repeat the question but that's a validator method is what you're asking about or like a validate interface valuer I'm not sure that I followed the question I'm sorry so I think the
question stopped me if I'm wrong I think the question was is it oh is it a good idea to define methods like is integer value or something for your Empty interfaces I yeah I don't think so I don't think it's a bad idea but I don't think it's necessary because the I don't have an example on here but because you can you should be able to type a cert in my in my opinion if you can't though if for some reason you really do just need to check if a value is a certain thing that's what type switching is for or types or type assertions with the optional ok parameter so I don't see the use in having a separate method but I may have misunderstood the the question anybody else oh right so the question is at what point could you type assert in the Marshall XML example and you really can't is the problem that's sort of why this was one of my early not a bad example it's a great example from the users perspective it's a very nice API but it's very bad from the from the developers perspective and the reason is like I said it's hard to type assert you
end up having to do this are lots of reflection to get because you can't type assert because you don't know what the type is you have to do a lot of reflection so it you can't is I think the answer I don't know a way not in this I I would love to know a better way to do the encoding package and go but I
haven't thought through that anybody else I guess that's it I'm sorry I'm very early thank you