Re: State should not depend on the API server

2014-09-16 Thread William Reade
On Thu, Sep 11, 2014 at 3:35 PM, Nate Finch nate.fi...@canonical.com wrote:
 I don't see how having different identical structs that are updated
 simultaneously in any way prevents any problems with compatibility.

If we're updating those structs simultaneously, we're completely
missing the point. Once we've defined a pure-data struct that might be
persisted or sent over the wire we *must not change that struct* -- if
we want to send or store different data, we need a new struct.

 Maybe I'm missing something from the proposal, but it seems like this just
 adds busywork without actually solving any problems that weren't caused by
 incorrect use of the code in the first place.

Isn't that tautological? AFAICS, storing a charm.Meta (or a
params.anything) directly in the DB *is* incorrect use of the code,
but nobody realises that until it's too late: that is the problem, and
that's what we're addressing.

 Separation of logic is absolutely a good thing.  Separation of data is not
 nearly so useful.

It's harder than you might think to separate the data from the logic
that acts on it ;).

Cheers
William

-- 
Juju-dev mailing list
Juju-dev@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/juju-dev


Re: State should not depend on the API server

2014-09-16 Thread David Cheney
On Tue, Sep 16, 2014 at 7:59 PM, William Reade
william.re...@canonical.com wrote:
 On Thu, Sep 11, 2014 at 3:35 PM, Nate Finch nate.fi...@canonical.com wrote:
 I don't see how having different identical structs that are updated
 simultaneously in any way prevents any problems with compatibility.

 If we're updating those structs simultaneously, we're completely
 missing the point. Once we've defined a pure-data struct that might be
 persisted or sent over the wire we *must not change that struct* -- if
 we want to send or store different data, we need a new struct.

 Maybe I'm missing something from the proposal, but it seems like this just
 adds busywork without actually solving any problems that weren't caused by
 incorrect use of the code in the first place.

 Isn't that tautological? AFAICS, storing a charm.Meta (or a
 params.anything) directly in the DB *is* incorrect use of the code,
 but nobody realises that until it's too late: that is the problem, and
 that's what we're addressing.

For example, apiserver/params.StateServingInfo was being stored
directly in the database. Woe to the person that updates the api only
to discover that data was silently deleted from the state database :(


 Separation of logic is absolutely a good thing.  Separation of data is not
 nearly so useful.

 It's harder than you might think to separate the data from the logic
 that acts on it ;).

 Cheers
 William

 --
 Juju-dev mailing list
 Juju-dev@lists.ubuntu.com
 Modify settings or unsubscribe at: 
 https://lists.ubuntu.com/mailman/listinfo/juju-dev

-- 
Juju-dev mailing list
Juju-dev@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/juju-dev


Re: State should not depend on the API server

2014-09-16 Thread Ian Booth


On 16/09/14 19:19, roger peppe wrote:
 On 16 September 2014 02:12, Tim Penhey tim.pen...@canonical.com wrote:
 On 12/09/14 01:35, Nate Finch wrote:
 Separation of logic is absolutely a good thing.  Separation of data is
 not nearly so useful.

 What I see as the real benefit of this work is based behind the
 interface segregation principle.

 Effectively this boils down to don't depend on things you don't need.
 
 I agree with this sentiment. Dependency hygiene is very important
 (though it seems to me that dependencies
 are perhaps more about implementation than interface).
 
 The state package should never depend on packages from the API.

 This work is not just busy work, but clear separation, and generally
 what is considered good software development principles.
 
 I have difficulty with this though. The state package and the API package
 are clearly linked - their concerns are not entirely separate. In my view,
 the state package exists only to serve the purposes of the API, which is
 *the* externally visible part of Juju.


There's a few issues here. The state package as it exists today is a mix of Juju
domain business logic and a persistence layer, unfortunately intertwined. What
should be the externally visible part of Juju is a service oriented abstraction
with coarse grained business methods; we have this with the facades. What comes
into those facades over the wire in terms of parameters should be transformed
into domain objects for use by the service business logic called by the facade
endpoints. On the wire data crosses a system boundary to enter/exit the business
services layer and so the data needs to be transformed to avoid unnecessary
coupling. As an example, a machine reference comes in over the wire as a machine
tag, which is transformed to a machine id for use by the services layer, which
us transformed to a global key when passed to the persistence layer. Thus the
api params structs contain attributes that are syntactically distinct from
what's required by the business services. It's a terrible abstraction leak to do
otherwise. Dave has started the process of correcting the implementation issue
we have, and in my view, it is necessary and desirable, based on sound design
principals. IMO :-)

 As such, many of the concerns and data structures dealt with by the state
 package will be the same as those dealt with by the API implementation.


This I disagree with - see above. The data structures should not be the same.

-- 
Juju-dev mailing list
Juju-dev@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/juju-dev


Re: State should not depend on the API server

2014-09-15 Thread Tim Penhey
On 12/09/14 01:35, Nate Finch wrote:
 Separation of logic is absolutely a good thing.  Separation of data is
 not nearly so useful.

What I see as the real benefit of this work is based behind the
interface segregation principle.

Effectively this boils down to don't depend on things you don't need.

The state package should never depend on packages from the API.

This work is not just busy work, but clear separation, and generally
what is considered good software development principles.

Tim


-- 
Juju-dev mailing list
Juju-dev@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/juju-dev


Re: State should not depend on the API server

2014-09-11 Thread roger peppe
On 11 September 2014 06:40, John Meinel j...@arbash-meinel.com wrote:
 ...
 I have thought for a while that, rather than writing more error-prone code
 (at  17k LOC, surely the API code is big enough as it is?), it would
 be good to create a tool that helps us with the underlying problem -
 incompatible changes made to marshaled types.

 This would not be too hard - the Go language already has such a tool
 (see http://golang.org/cmd/api/ ), although it is not currently generally
 applicable.

 This could make it possible to provide a much stronger assurance about
 compatibility, including compatibility between types not defined inside
 juju-core itself, while keeping the code natural and simple.

   cheers,
 rog.


 So that is interesting, and it might be fruitful to explore. I'll just note
 that it is actually a pretty small (and reasonably obvious) part of API
 compatibility. It *doesn't* tell you

 1) If passing an empty string suddenly has a different meaning (see
 Client.ServiceSet where we used to treat  as meaning reset-to-default vs
 Client.NewServiceSetForAPI where we wanted to actually treat  as meaning
 set this value to the empty string.)

 2) Returning a new value (Machine.Jobs(), we want to add new Jobs for new
 behaviors and don't want to confuse old agents until they have finished
 upgrading).

Yes, I agree. There are aspects of compatibility that
cannot be checked automatically, and we always need
to be careful when changing semantics. I don't
think there's any way around that.

 So while something like the above could tell you has the shape of the API
 changed, and what I really like about it is that if it had a collapsed view
 (like a simple text representation), it is easy to keep that around in the
 source tree and use it for reference.

Yes, that's a nice thing about the Go api command, which does
use a simple text representation.

 However, you really do need tests for (1) and (2). (1) we actually broke
 accidentally because we changed the code inside of state/*, and then had to
 go back and retrofit the API to use a new code path to preserve
 compatibility.

Yup.

 And if you need tests, you really still need 2 types to represent the
 different versions, and if you already need those types, then I would
 recommend having a regular structure for them.

Here's where I don't agree. I don't think, for example, that it's worth
creating a new type just because its Jobs field can take on a value
that it could not previously have. We might need a new version of the API, sure
(although even that might be arguable in this case - agents just ignore
unknown job types), but defining a new type seems like overkill to me.

Even when we do need to make a new type, I don't really see why
having a different type at each level will help us. One will probably
need to make the new type at every level too, so having the
differently defined types isn't a great benefit over having
a single changed type.

There will of course be cases when we *do* want different types
at different levels, but that's easy to do on a case-by-case basis.
I suggest using appropriate types at the different levels
*as required by those levels*, rather than expending developer time and
generating extra runtime garbage by copying identical representations
of the same data around for every single type at every level.

  cheers,
rog.

-- 
Juju-dev mailing list
Juju-dev@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/juju-dev


Re: State should not depend on the API server

2014-09-11 Thread Nate Finch
I have been in situations in past jobs where adding one field to one
logical entity required changing the signature of a half dozen structures 
functions that were just copying data back and forth for little to no
benefit.  This is a pain in the ass, error prone, and should be avoided.

One of the things I like best about Go is that structs can be just data.
 How you interact with the data can be different from layer to layer, but
there's no reason why we need different structs with the same layout in
different packages just for the illusion of separation of concerns.  If you
modify one, you have to modify all of them, thus you might as well just
have one they all use.  At least then it's clear which places in the code
depend on this logical data structure, rather than having to try to grep
for everywhere we copy the data from one structure to another.  This is why
having the api/params leaf package is a good idea - it's just data.  Any
package can use those structs to layout their data in a way that other
packages can understand.

I don't see how having different identical structs that are updated
simultaneously in any way prevents any problems with compatibility.

If they're different structs, they cannot possibly actually represent the
same data on both sides of the wire, can they?  One or both of the structs
must have information that is not present on the wire and that information
should be in a different type (which may embed the wire-data-struct).

Maybe I'm missing something from the proposal, but it seems like this just
adds busywork without actually solving any problems that weren't caused by
incorrect use of the code in the first place.

Separation of logic is absolutely a good thing.  Separation of data is not
nearly so useful.

On Thu, Sep 11, 2014 at 3:46 AM, roger peppe roger.pe...@canonical.com
wrote:

 On 11 September 2014 06:40, John Meinel j...@arbash-meinel.com wrote:
  ...
  I have thought for a while that, rather than writing more error-prone
 code
  (at  17k LOC, surely the API code is big enough as it is?), it would
  be good to create a tool that helps us with the underlying problem -
  incompatible changes made to marshaled types.
 
  This would not be too hard - the Go language already has such a tool
  (see http://golang.org/cmd/api/ ), although it is not currently
 generally
  applicable.
 
  This could make it possible to provide a much stronger assurance about
  compatibility, including compatibility between types not defined inside
  juju-core itself, while keeping the code natural and simple.
 
cheers,
  rog.
 
 
  So that is interesting, and it might be fruitful to explore. I'll just
 note
  that it is actually a pretty small (and reasonably obvious) part of API
  compatibility. It *doesn't* tell you
 
  1) If passing an empty string suddenly has a different meaning (see
  Client.ServiceSet where we used to treat  as meaning reset-to-default
 vs
  Client.NewServiceSetForAPI where we wanted to actually treat  as
 meaning
  set this value to the empty string.)
 
  2) Returning a new value (Machine.Jobs(), we want to add new Jobs for new
  behaviors and don't want to confuse old agents until they have finished
  upgrading).

 Yes, I agree. There are aspects of compatibility that
 cannot be checked automatically, and we always need
 to be careful when changing semantics. I don't
 think there's any way around that.

  So while something like the above could tell you has the shape of the
 API
  changed, and what I really like about it is that if it had a collapsed
 view
  (like a simple text representation), it is easy to keep that around in
 the
  source tree and use it for reference.

 Yes, that's a nice thing about the Go api command, which does
 use a simple text representation.

  However, you really do need tests for (1) and (2). (1) we actually broke
  accidentally because we changed the code inside of state/*, and then had
 to
  go back and retrofit the API to use a new code path to preserve
  compatibility.

 Yup.

  And if you need tests, you really still need 2 types to represent the
  different versions, and if you already need those types, then I would
  recommend having a regular structure for them.

 Here's where I don't agree. I don't think, for example, that it's worth
 creating a new type just because its Jobs field can take on a value
 that it could not previously have. We might need a new version of the API,
 sure
 (although even that might be arguable in this case - agents just ignore
 unknown job types), but defining a new type seems like overkill to me.

 Even when we do need to make a new type, I don't really see why
 having a different type at each level will help us. One will probably
 need to make the new type at every level too, so having the
 differently defined types isn't a great benefit over having
 a single changed type.

 There will of course be cases when we *do* want different types
 at different levels, but that's easy to do on a 

Re: State should not depend on the API server

2014-09-10 Thread John Meinel

 ...
 I have thought for a while that, rather than writing more error-prone code
 (at  17k LOC, surely the API code is big enough as it is?), it would
 be good to create a tool that helps us with the underlying problem -
 incompatible changes made to marshaled types.

 This would not be too hard - the Go language already has such a tool
 (see http://golang.org/cmd/api/ ), although it is not currently generally
 applicable.

 This could make it possible to provide a much stronger assurance about
 compatibility, including compatibility between types not defined inside
 juju-core itself, while keeping the code natural and simple.

   cheers,
 rog.


So that is interesting, and it might be fruitful to explore. I'll just note
that it is actually a pretty small (and reasonably obvious) part of API
compatibility. It *doesn't* tell you

1) If passing an empty string suddenly has a different meaning (see
Client.ServiceSet where we used to treat  as meaning reset-to-default vs
 Client.NewServiceSetForAPI where we wanted to actually treat  as meaning
set this value to the empty string.)

2) Returning a new value (Machine.Jobs(), we want to add new Jobs for new
behaviors and don't want to confuse old agents until they have finished
upgrading).

So while something like the above could tell you has the shape of the API
changed, and what I really like about it is that if it had a collapsed
view (like a simple text representation), it is easy to keep that around in
the source tree and use it for reference.

However, you really do need tests for (1) and (2). (1) we actually broke
accidentally because we changed the code inside of state/*, and then had to
go back and retrofit the API to use a new code path to preserve
compatibility.

And if you need tests, you really still need 2 types to represent the
different versions, and if you already need those types, then I would
recommend having a regular structure for them.

John
=:-
-- 
Juju-dev mailing list
Juju-dev@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/juju-dev


Re: State should not depend on the API server

2014-09-08 Thread roger peppe
On 1 September 2014 06:40, David Cheney david.che...@canonical.com wrote:
 Hello,

 This is an introductory email to explain my upcoming series of pull requests.

 The theme is simple: state must not depend on the api server.

 This is currently not true, state depends on api/params because some
 of the api types have leaked into the state package and are being
 directly stored in mongo.

 Please speak up if you disagree with this proposal.

Sorry for not replying earlier. I'm just back from a week's holiday.

I'm not sure I agree with the thrust of this proposal.

The api/params package is not the API server - it's a leaf package
defining types that may be used by the API server.  Thus state does not
in fact depend on the api server.

Furthermore, I am not convinced that redefining the same types in
different places is a great help. It means there's more maintenance,
and more chance of getting things wrong when writing the code to convert
between them.

Go makes it easy to define a single type that defines the marshaling
format for both client and server sides. This seems to me to be a Good
Thing. Within a single code base, surely a given version of the API can
define the parameters for the client and server side in the same way,
for example?

What we really want to do here, IMHO, is guard against incompatible
changes made to types that are persistently used, whether that's because
they're stored in mongo or used to communicate with other versions of
the API server.

I have thought for a while that, rather than writing more error-prone code
(at  17k LOC, surely the API code is big enough as it is?), it would
be good to create a tool that helps us with the underlying problem -
incompatible changes made to marshaled types.

This would not be too hard - the Go language already has such a tool
(see http://golang.org/cmd/api/ ), although it is not currently generally
applicable.

This could make it possible to provide a much stronger assurance about
compatibility, including compatibility between types not defined inside
juju-core itself, while keeping the code natural and simple.

  cheers,
rog.

-- 
Juju-dev mailing list
Juju-dev@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/juju-dev


Re: State should not depend on the API server

2014-09-02 Thread Eric Snow
On Mon, Sep 1, 2014 at 12:03 AM, John Meinel j...@arbash-meinel.com wrote:
 FWIW I'd favor 3 layers, though it does mean you have to do copying between
 structs that would likely otherwise be almost identical. A State layer for
 saving in the DB, an API layer for communication, and a Model layer for use
 in the Agents/Clients.

This is pretty much what I've done for the new backups in response to
conversations with Menno and William.  It's worked out fine.  The 3
types are similar, but in each case have been slightly different.  So
the choice of having them different has proved helpful.

-eric

-- 
Juju-dev mailing list
Juju-dev@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/juju-dev


Re: State should not depend on the API server

2014-09-01 Thread John Meinel
FWIW I'd favor 3 layers, though it does mean you have to do copying between
structs that would likely otherwise be almost identical. A State layer for
saving in the DB, an API layer for communication, and a Model layer for use
in the Agents/Clients.

John
=:-



On Mon, Sep 1, 2014 at 9:40 AM, David Cheney david.che...@canonical.com
wrote:

 Hello,

 This is an introductory email to explain my upcoming series of pull
 requests.

 The theme is simple: state must not depend on the api server.

 This is currently not true, state depends on api/params because some
 of the api types have leaked into the state package and are being
 directly stored in mongo.

 Please speak up if you disagree with this proposal.

 Dave

 --
 Juju-dev mailing list
 Juju-dev@lists.ubuntu.com
 Modify settings or unsubscribe at:
 https://lists.ubuntu.com/mailman/listinfo/juju-dev

-- 
Juju-dev mailing list
Juju-dev@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/juju-dev


Re: State should not depend on the API server

2014-09-01 Thread David Cheney
The goal I have been tasked with is breaking the interdependency
between the state package and the _client_ api types in
state/api/params.

I don't have any opinion on adding additional layers assuming that
their dependancies flow downwards, ie

labix.org/mgo - juju/state - juju/apiserver

On Mon, Sep 1, 2014 at 4:03 PM, John Meinel j...@arbash-meinel.com wrote:
 FWIW I'd favor 3 layers, though it does mean you have to do copying between
 structs that would likely otherwise be almost identical. A State layer for
 saving in the DB, an API layer for communication, and a Model layer for use
 in the Agents/Clients.

 John
 =:-



 On Mon, Sep 1, 2014 at 9:40 AM, David Cheney david.che...@canonical.com
 wrote:

 Hello,

 This is an introductory email to explain my upcoming series of pull
 requests.

 The theme is simple: state must not depend on the api server.

 This is currently not true, state depends on api/params because some
 of the api types have leaked into the state package and are being
 directly stored in mongo.

 Please speak up if you disagree with this proposal.

 Dave

 --
 Juju-dev mailing list
 Juju-dev@lists.ubuntu.com
 Modify settings or unsubscribe at:
 https://lists.ubuntu.com/mailman/listinfo/juju-dev



-- 
Juju-dev mailing list
Juju-dev@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/juju-dev


Re: State should not depend on the API server

2014-09-01 Thread Ian Booth

On 01/09/14 16:03, John Meinel wrote:
 FWIW I'd favor 3 layers, though it does mean you have to do copying between
 structs that would likely otherwise be almost identical. A State layer for
 saving in the DB, an API layer for communication, and a Model layer for use
 in the Agents/Clients.


This is my wish too. A sane, layered architecture, devoid of inappropriate
coupling between layers, and a proper separation of concerns; the result of
which will lead to, amongst other things, much better and faster, true unit
tests. Well, there's a bit more that needs fixing first, eg more IOC, less use
of concrete structs etc, but our current woes with unreliable tests is directly
attributable to the fact that we often need to bring up the entire stack to test
a component.

So any progress towards fixing things, in this case eliminating unnecessary and
inappropriate coupling between state and api server is much appreciated.


 John
 =:-
 
 
 
 On Mon, Sep 1, 2014 at 9:40 AM, David Cheney david.che...@canonical.com
 wrote:
 
 Hello,

 This is an introductory email to explain my upcoming series of pull
 requests.

 The theme is simple: state must not depend on the api server.

 This is currently not true, state depends on api/params because some
 of the api types have leaked into the state package and are being
 directly stored in mongo.

 Please speak up if you disagree with this proposal.

 Dave

 --
 Juju-dev mailing list
 Juju-dev@lists.ubuntu.com
 Modify settings or unsubscribe at:
 https://lists.ubuntu.com/mailman/listinfo/juju-dev

 
 
 

-- 
Juju-dev mailing list
Juju-dev@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/juju-dev


Re: State should not depend on the API server

2014-09-01 Thread William Reade
On Mon, Sep 1, 2014 at 8:03 AM, John Meinel j...@arbash-meinel.com wrote:
 FWIW I'd favor 3 layers, though it does mean you have to do copying between
 structs that would likely otherwise be almost identical. A State layer for
 saving in the DB, an API layer for communication, and a Model layer for use
 in the Agents/Clients.

Yes please, in general: one set of types per layer boundary.
Independent of what Dave's doing, which is necessary regardless, I
agree with what you're saying: *except* that I think we really have to
consider the API layer to be *two* layers.

That is to say: if you can change some type in api/params and
everything still works, you are Doing It Wrong. We cannot depend on
servers and clients always running the same version -- so, every time
you thus change server/client in a single motion, you're almost
certainly introducing more or less subtle incompatibilities.

So, I would be very pleased if we would stop using the same
definitions (ie api/params) on both sides of the wire -- it's one of
those things that's nice and easy when everyone's running the same
version, but an active trap as soon as multiple versions exist (as
they do).

All the struct-copying is kinda boring, but the layering violations
are straight-up evil.

Dave, thanks very much for doing this.

Cheers
William

-- 
Juju-dev mailing list
Juju-dev@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/juju-dev


Re: State should not depend on the API server

2014-09-01 Thread John Meinel
...



 So, I would be very pleased if we would stop using the same
 definitions (ie api/params) on both sides of the wire -- it's one of
 those things that's nice and easy when everyone's running the same
 version, but an active trap as soon as multiple versions exist (as
 they do).

 All the struct-copying is kinda boring, but the layering violations
 are straight-up evil.


Yeah, we've started running into this a bit as we get into actually revving
versions in the API (as yet, we haven't actually bumped an api version
though all the infrastructure should be there.)

John
=:-



 Dave, thanks very much for doing this.

 Cheers
 William

-- 
Juju-dev mailing list
Juju-dev@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/juju-dev


State should not depend on the API server

2014-08-31 Thread David Cheney
Hello,

This is an introductory email to explain my upcoming series of pull requests.

The theme is simple: state must not depend on the api server.

This is currently not true, state depends on api/params because some
of the api types have leaked into the state package and are being
directly stored in mongo.

Please speak up if you disagree with this proposal.

Dave

-- 
Juju-dev mailing list
Juju-dev@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/juju-dev