<p dir="ltr">That specific problem (struct A returning concrete struct B objects), definitely came up in our struct vs interface discussions. It might be better to have it as a free function rather than a method on Machine. Like a<br>
func UnitsForMachine (machine interface {Tag ()}) [] Unit</p>
<p dir="ltr">The problem with interfaces at this level, though, is that it is one of those "anyone that needs some attribute of Unit might use this function".</p>
<p dir="ltr">So I would tend to say, we arent set up to mock at this level. Instead write your new code to take a factory func rather than assuming it is a method of the types passed in. (interface definitions are intentionally not recursive, but the factory shim should be small)</p>
<p dir="ltr">John<br>
=:-></p>
<div class="gmail_quote">On Nov 1, 2013 5:42 AM, "Andrew Wilkins" <<a href="mailto:andrew.wilkins@canonical.com">andrew.wilkins@canonical.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div dir="ltr">On Thu, Oct 31, 2013 at 8:57 PM, John Arbash Meinel <span dir="ltr"><<a href="mailto:john@arbash-meinel.com" target="_blank">john@arbash-meinel.com</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">-----BEGIN PGP SIGNED MESSAGE-----<br>
Hash: SHA1<br>
<div><div><br>
On 2013-10-31 16:21, Andrew Wilkins wrote:<br>
> Does anybody object to converting the public entity structs in<br>
> state to interfaces? i.e. State, Machine, Unit, etc.<br>
><br>
> I'd like to write some tests for new code that depends on state.<br>
> Setting up mongo and so on is overkill. and should be relegated to<br>
> integration testing.<br>
><br>
> Cheers, Andrew<br>
><br>
><br>
<br>
</div></div>I would say that if you want an interface you probably don't need the<br>
whole set of functions that Unit/Machine/etc provide. And a smaller<br>
interface means you don't have to create a fake one that has a bunch<br>
of methods you don't actually use.<br></blockquote><div><br></div><div>Agreed. I would prefer not to convert them to interfaces at all, and have only interfaces at the usage site. However, the way the structs are interrelated is problematic. In my specific use case, I really only care about the following hypothetical interfaces. They're being used to clean up an environment (destroy all units, wait for them to disappear, then destroy all machines without JobHostEnviron and wait for them to disappear).</div>
<div><br></div><div>----------------- 8< -------------------<br></div><div><br></div><div>type State interface {</div><div> AllMachines() ([]Machine, error)</div><div>}</div><div><br></div><div>// another name would be needed, as this clashes with state.Entity; just for demonstration</div>
<div>type Entity interface {</div><div> Tag() string</div><div> Destroy() error</div><div> Refresh() error</div><div>}</div><div><br></div><div>type Machine interface {</div><div> Entity</div><div> Units() ([]Unit, error)</div>
<div> Jobs() []MachineJob</div><div>}</div><div><br></div><div>type Unit interface {</div><div> Entity</div><div> IsPrincipal() bool</div><div>}<br></div><div><br></div><div>----------------- 8< -------------------</div>
<div><br></div><div>If it weren't for State.AllMachines and Machine.Units, I wouldn't have even asked the question. The problem is that these methods' signatures would need to change to return interfaces. Then once you do that, you're destined to implement everything as an interface. For the structs to implement an external interface, the structs (as they are now) would need to be wrapped, and then you're back to duplicating everything again.</div>
<div> </div><div>Another option would be to add a couple of new methods: State.AllMachineNames(), and Machine.UnitNames(), which return []strings. This isn't great either, as it means duplicating work (at least two trips to the database, when one would do).</div>
<div><br></div><div>Thanks for the feedback. Creating huge interfaces didn't sound great to me either, but I'm not sure what a good alternative is here. I'll have to think some more about it... if anyone has a reasonable solution, please let me know.</div>
<div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
Something to think about, at least.<br>
<br>
I personally like having interfaces, but I'm not sure that all of<br>
Unit/Machine/etc need to be turned into an interface. There are<br>
already a few that we have (like Entity, etc).<br>
<br>
John<br>
=:-><br>
-----BEGIN PGP SIGNATURE-----<br>
Version: GnuPG v1.4.13 (Cygwin)<br>
Comment: Using GnuPG with Thunderbird - <a href="http://www.enigmail.net/" target="_blank">http://www.enigmail.net/</a><br>
<br>
iEYEARECAAYFAlJyU64ACgkQJdeBCYSNAAMJPQCg2D+tL2gx2+U4cYFBsnf9/uQW<br>
ofsAnjnS8bgxEd560bI0N80ilFdFFaxK<br>
=stRr<br>
-----END PGP SIGNATURE-----<br>
</blockquote></div><br></div></div>
</blockquote></div>