On 09/05/2013, at 12:51 AM, Adam Murdoch <adam.murd...@gradleware.com> wrote:
> Hi, > > Just revisiting the old 'how do we deal with names for domain objects' > question. > > Currently, our polymorphic container is-a NamedDomainObjectContainer. As such > it forces every domain object to have a unique name. The problem with this > approach is that I need to encode the type into the name. > > For example, we are planning to use a `binaries` container to own all the > binaries produced by the project. If I have a `main` Java library, then we > need to add (by convention) a `mainClasses` ClassesDirectory binary and a > `mainJar` Jar binary for this library. If I have a `main` Groovy library > built for Groovy 1.8 and Groovy 2.0, then I need to add `mainGroovy18Classes` > and `mainGroovy20Classes` and `mainGroovy18Jar` and `mainGroovy20Jar`. If I > have a `main` C library built for windows and linux with 32-bit and 64-bit > and static and shared and debug and release variants, well… then we need lots > of names. > > I'd like to change things so we can get rid of the type from the name. This, > of course, still leaves the other dimensions packed into the name. We don't > have a good solution for this yet, but I suspect one will emerge. > > The approach I'd like to take (which isn't a new idea - can't remember who > suggested it) is to make (name, type) the unique identifier for a thing. > > The DSL for defining an object would change from this: > > binaries { > mainStaticLibrary(StaticLibraryBinary) { … } > mainSharedLibrary(SharedLibraryBinary) { … } > } > > To: > > binaries { > staticLibraries { > main { … } > } > sharedLibraries { > main { … } > } > } > > Also: > > publications { > maven { > main { … } > } > ivy { > main { … } > } > } > > > To find something: > > // look something up by name > def main = binaries.main // fails if there are multiple binaries with name > `main` > > // look something up by type and name > def main = binaries.staticLibraries.main > > // look something up by super type and name > def main = binaries.nativeLibraries.main // fails if there are multiple > native libraries with name `main` Are we automatically doing the lookup here? i.e. drop package, camel case and pluralise? Or is there an explicit mapping between a type and its "dsl name"? > // look up all things by type > def libs = binaries.staticLibraries > > And to deal with the other dimensions, you'd use the existing collection > stuff: > > // All windows static libs > def libs = binaries.staticLibraries.matching { it.platform.operatingSystem == > operatingSystems.windows } > > We can come up with conveniences for the other dimensions. Perhaps a > map-based selector: > > def libs = binaries.staticLibraries(platform.operatingSystem: > operatingSystems.windows) > > Thoughts? I don't think this plan quite gets it right, but it feels better > than the current DSL. I don't think it really fixes the problem. I think we want to get away from the idea of an immutable name altogether. Instead, we probably want a way to extract an identifier based on differentiating characteristics. This seems to be how the names are used as we've discussed. Combining this with some of deferred configuration stuff, I think you want to tell Gradle which characteristics to use to construct the identifier. This also means you don't have to predict names. Disclaimer: I haven't really thought this through beyond reading this email. Let's say we have the following interface: interface Identifiable { String getIdentifier() void setIdentifier(String identifierPattern) } An identifier pattern is a tokenisable (at runtime) string, based on properties of the thing… class HttpRepository extends AbstractIdentifiable { … String getUrl() } def repository = new HttpRepository(url: "http://org.com") repository.identifier = "#url" assert repository.identifier == "http://org.com" The benefit here is that types can supply a default naming strategy, which could be based on important characteristics. Assuming that we find some way to actually "lock" objects after they've been configured with the deferring stuff, we could also make the actual value immutable at this time. We could defer preventing collisions until this point. The idea is also that the identifier is only used for output and for deriving names (would be good if we could avoid this in the future too). If you are programmatically looking for something, you find it by looking up characteristics. I don't think plugins do this often anyway. It doesn't seem often to me that infrastructure code pulls objects from containers via their name. You're usually agnostic to containers at this level and work directly with the instances. Configurers (a.k.a users) do this all the time, but they should have the knowledge required to identify the thing they want. If you add in a singleFile type approach here (i.e. I'm expecting there to be one thing in this collection and I want it) then I think it would work. While we are discussing the DSL we should also consider making creation explicit. We have the same problem with our domain object containers as we did with dynamic properties. Namely, we can't tell if the user wants to create something or configure an existing thing and therefore can't detect typos or tell the user that that thing doesn't actually exist. Another idea that I had (not related to above paragraph) was formalising the concept of a lookup path. This could be used to avoid duplication… publications(IvyPublication, group: "org.foo", version: "1.0") { add { module "a" } add { module "b" } add { module "c" } } So publications(IvyPublication, group: "org.foo", version: "1.0") {} creates a kind of context that is inherited during the closure. All things created in this closure get these properties. Could also be used for filtering/configuring: publications(IvyPublication, group: "org.foo", version: "1.0") { find(module: "a") find(module: "b") … } I suspect that situation is also reasonably describable via DSLD and whatever the IDEA equivalent is. -- Luke Daley Principal Engineer, Gradleware http://gradleware.com Join me at the Gradle Summit 2013, June 13th and 14th in Santa Clara, CA: http://www.gradlesummit.com --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email