tag:robotlegs.tenderapp.com,2009-10-18:/discussions/questions/323-some-concernsquestions-about-signalsRobotlegs: Discussion 2018-10-18T16:35:18Ztag:robotlegs.tenderapp.com,2009-10-18:Comment/33505832010-10-14T08:19:52Z2010-10-14T08:19:52ZSome concerns/questions about Signals<div><p>Hi Creynders...</p>
<blockquote><p>I'm creating an application with Signals for the first time and although they have a lot of benefits, there are a few things that are a bit concerning I think. But maybe it's because I don't know how to use them properly.</p></blockquote>
<p>Yup - your email does suggest that you're a bit confused about Signals!</p>
<p>So... here goes on Signals 101:</p>
<p>I think it's possible - as with any other code - to abuse Signals. They're very powerful and you can choose to use them for dangerous shortcuts. But the same could be said of DI generally.</p>
<p>On your concerns:</p>
<p>1) If you get the amount of payload incorrect, you'll get a noisy error at the 'add' stage (not just when the dispatch fails). If you get the dispatch arguments incorrect you'll get a noisy error telling you what it was expecting. <br />
</p>
<p>Signals have a public function getValueClasses() which will list out all the values they expect. You can use this to find any mystery values if you have undocumented swc code. If the Signal is further wrapped, so you can't see it publicly, then you don't need access to it so the values are irrelevant to you (as you'll never add or dispatch).</p>
<p>You can also unit test the signal relationship at both ends (and I do). Signals are even easier than events to unit test around.</p>
<p>2) Why is there a problem with</p>
<pre><code>[Inject]
public var myVar:String;</code></pre>
<p>in a Command?</p>
<p>Commands, and the injections into Commands, are short lived. The injection is created, the Command is instantiated, the injection is destroyed, the Command is executed, and then the Command dies. If you had a String payload on an Event using the Command/Event map, that works in the exact same way.</p>
<p>I can't see the problem... (unless it's automagic DI generally that is making you shudder?). SignalCommands are where I would advocate the use of base types for injections (assuming you're not littering your app with base type injections generally - in which case you could do with going back to auto-DI 101 instead).</p>
<p>Just as with the Event/Command map, if you have 2 params of the same type then you need to create a VO to wrap your params. That's a constraint of auto-DI, not a constraint of Signals.</p>
<p>3) I'm afraid I can't really understand the problem here... perhaps once you've understood 1 & 2 a bit better this concern will not seem so big. Apart from anything else, if you've got a significantly sized app you would be better to be breaking your mappings down into Commands mapped to Startup - so you can have a BootstrapSignalsCommand with the signalCommandMap mappings and the mapSingleton mappings for your Signals all nicely grouped together.</p>
<p>Overall - your concerns make me wonder whether you're using TDD (or even Unit Testing). All code breaks if you forget or delete something you needed. We could make the same statements as you've made about removing a mapping (and the mediator breaking, and needing to keep track of what is required where) about not initialising a variable. A lot of broken code will only throw a null error at runtime, or fail silently for a while before you get an error later, which is why test coverage is so useful in AS3.</p>
<p>I've been using Signals a lot for quite a long time on a huge project. They have yet to disappoint / worry me. I don't think I've ever had a Signal related problem since I got the hang of them. They are also particularly awesome for view-mediator relationships as they allow complex views to send multiple messages to the mediator without the mediator knowing anything about that view (except what signals it has), or the view exposing its internals inappropriately.</p>
<p>You're right - there are imperfections - but I think these are weaknesses of AS3 as a language, not of Signals. If you want more compile time checking by the way you can wrap your dispatch in a strong typed signal with a function with the declared args. Eg</p>
<pre><code>dispatchStrongSignal(width:Number, color:uint):void
{
dispatch(width, color);
}</code></pre>
<p>This is similar to the issues we face when using the comboBox component for example - if you want your comboBox to only hold values of a certain type, you have to wrap it.</p>
<p>Unfortunately there's no way that I've found to compile time check the function you add to a Signal. At runtime you could use describeType() of the parent object to validate the listener, but that would be expensive and you'd be way better off just using unit testing!</p>
<p>So ... hopefully this is enough for you to give Signals a bit more time.</p>
<p>Stray</p></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/33505832010-10-14T10:36:24Z2010-10-23T09:55:13ZSome concerns/questions about Signals<div><blockquote><p>1) If you get the amount of payload incorrect, you'll get a noisy error at the 'add' stage (not just when the dispatch fails). If you get the dispatch arguments incorrect you'll get a noisy error telling you what it was expecting.</p></blockquote>
<p>I didn't even know it was possible to get the number of arguments of a function outside the function.<br />
<code>// function.length is the number of arguments.</code></p>
<p>Anyway, these are all RTE and I'd really prefer CTE's.</p>
<blockquote><p>Why is there a problem with</p></blockquote>
<pre><code>[Inject]
public var myVar:String;</code></pre>
<p>Because it goes against the 'normal' rule, where anonymous base type injections are restricted to one possible value.</p>
<blockquote><p>Just as with the Event/Command map, if you have 2 params of the same type then you need to create a VO to wrap your params. That's a constraint of auto-DI, not a constraint of Signals.</p></blockquote>
<p>True.</p>
<blockquote><p>BootstrapSignalsCommand with the signalCommandMap mappings and the mapSingleton mappings for your Signals all nicely grouped together.</p></blockquote>
<p>True, that's a good solution and I'll be using that.</p>
<blockquote><p>Overall - your concerns make me wonder whether you're using TDD (or even Unit Testing).</p></blockquote>
<p>Hehe, nice catch! I somehow don't seem to be able to wrap my head around the concept when going from tutorials to real-life project. I'm unsure about what to test and how. I've toyed a few times with AsUnit, but I don't see how to make the step to real production. (Reminds me of MVC, it literally took me a few years before I understood how to transfer the extremely simple examples to real-life applications and TBH I still struggle with it)</p></div>creynderstag:robotlegs.tenderapp.com,2009-10-18:Comment/33505832010-10-14T12:03:27Z2010-10-14T12:03:27ZSome concerns/questions about Signals<div><blockquote><blockquote><p>1) If you get the amount of payload incorrect, you'll get a noisy error at the 'add' stage (not just when the dispatch fails). If you get the dispatch arguments incorrect you'll get a noisy error telling you what it was expecting.</p></blockquote>
<p>I didn't even know it was possible to get the number of arguments of a function outside the function.
<code>// function.length is the number of arguments.</code></p>
<p>Anyway, these are all RTE and I'd really prefer CTE's.</p></blockquote>
<p>Don't we all. But Flash offers zero CTE protection for Errors, and Signals provides superior RTE protection to the native Event system - so, within the constraints of the language and the compiler, I think Signals does the best job possible. At least it avoids listening for something that will never happen. With the native flash Event system, I can listen for IOErrorEvent on a DisplayObject!</p>
<blockquote><blockquote><p>Why is there a problem with</p></blockquote>
<p> [Inject]
public var myVar:String;</p>
<p>Because it goes against the 'normal' rule, where anonymous base type injections are restricted to one possible value.</p></blockquote>
<p>I'd say the rule is that <em>at any given moment in time</em> it's possible to only have one anonymous base type injection - and given that this is temporary and short-lived, it doesn't break the rules.</p>
<blockquote><blockquote><p>Just as with the Event/Command map, if you have 2 params of the same type then you need to create a VO to wrap your params. That's a constraint of auto-DI, not a constraint of Signals.</p></blockquote>
<p>True.</p>
<blockquote><p>BootstrapSignalsCommand with the signalCommandMap mappings and the mapSingleton mappings for your Signals all nicely grouped together.</p></blockquote>
<p>True, that's a good solution and I'll be using that.</p>
<blockquote><p>Overall - your concerns make me wonder whether you're using TDD (or even Unit Testing).</p></blockquote>
<p>Hehe, nice catch! I somehow don't seem to be able to wrap my head around the concept when going from tutorials to real-life project. I'm unsure about what to test and how. I've toyed a few times with AsUnit, but I don't see how to make the step to real production. (Reminds me of MVC, it literally took me a few years before I understood how to transfer the extremely simple examples to real-life applications and TBH I still struggle with it)</p></blockquote>
<p>No pain no gain! It's a learning curve - just like any other. Learning to write useful tests is just as hard (harder maybe) as writing the code that fulfils the tests.</p>
<p>What to test: Everything API that is dependent on the code you are about to write. (Don't test the framework, don't test your utilities that come with their own tests etc). Some people say don't test accessors but I find accessor testing useful in catching simple errors.</p>
<p>How to test:</p>
<ul>
<li><p>Use simple asserts (assertTrue / assertEquals) to test API functions that return something, or that an error is thrown when it should be.</p></li>
<li><p>Use async tests to verify that expected events are fired on the shared eventDispatcher, and then asserts in the handlers to verify event payload etc.</p></li>
<li><p>Use mocking of interfaces to verify integration (for example that a Command has performed a mapping on the injector).</p></li>
<li><p>Write your tests before you write the code. The action of writing the test includes the 'thinking' part that helps you plan what code to write. This is why it feels hard.</p></li>
</ul>
<p>Do:</p>
<ul>
<li><p>Apply the same standards to your test code as to your app code, otherwise it will be brittle and hard to change.</p></li>
<li><p>Use helper functions to minimise code repetition.</p></li>
<li><p>Create helper objects to encapsulate what varies. For example, create a class SomeTypeSupport(key:uint=1) to wrap a the SomeType class which has constructor params, so that if the constructor params change you only have to change inside the Support class and not every single place you instantiated that type. (The key in this example allows you to create many SomeType object with different properties if you need that for your test).</p></li>
<li><p>Use constants to represent values that don't need to change in the course of the test - this will also make it easier for you to write asserts that verify that these values have been stored as you only have to remember what the value <em>is</em> and not the actual value. eg:</p>
<p>assertEquals("returns correct value for multiplication", INPUT_A * INPUT_B, instance.multiply(INPUT_A, INPUT_B));</p></li>
<li><p>Build yourself a library of reused matchers / test helpers as you go - for example I have UnitHelpers.clickThisItemInComboBox() and UnitHelpers.objectContainsAnInstanceOf() so on.</p></li>
<li><p>Refactor your tests when you realise they could be less brittle.</p></li>
<li><p>Write baby tests that get you part way, or explore unknowns, as a tool for understanding the problem space enough to write the final tests.</p></li>
<li><p>Be prepared to suck at writing tests while you get better at it. Ask questions, read books, write blogs as you find stuff out and do all the usual stuff to acquire expertise.</p></li>
</ul>
<p>Don't:</p>
<ul>
<li><p>Panic when it seems hard. Testing <em>should</em> be hard - because it front loads all the really difficult cognitive stuff by forcing you to work out what you are really trying to do. Writing code is easy - it's deciding what code to write that's the hard part, and tests force that pain nearer the beginning.</p></li>
<li><p>Write test code that you wouldn't accept in an application.</p></li>
<li><p>Skip the hard tests, thinking you'll write them after. You won't.</p></li>
<li><p>Get caught up in instantiating expensive objects just to fulfil the dependencies of the class you're testing - use mocking/stubbing to fulfil those requirements instead.</p></li>
<li><p>Set yourself up to fail by using TDD for the first time on a project with a crazy deadline. Start out with opportunities to back track.</p></li>
<li><p>Think you have to figure everything out for yourself. Ask people who do TDD how they would approach things when you get stuck.</p></li>
</ul>
<p>Stray!</p>
<blockquote><h2>View this Discussion online: <a href="http://knowledge.robotlegs.org/discussions/questions/323-some-concernsquestions-about-signals">http://knowledge.robotlegs.org/discussions/questions/323-some-conce...</a></h2>
<p>You can use commands on a new line at the top of this email.
Available commands: #resolve #acknowledge #spam #delete #queue #notify #ignore #public #private
More information: <a href="https://help.tenderapp.com/faqs/email-integration/commands">https://help.tenderapp.com/faqs/email-integration/commands</a></p></blockquote></div>Straytag:robotlegs.tenderapp.com,2009-10-18:Comment/33505832010-10-14T12:46:10Z2010-10-23T09:55:13ZSome concerns/questions about Signals<div><p>Again, thanks for your help Stray, what a splendid explanation. These are exactly the kind of tips i've been lacking to start out. When this project is finished I'm going to tackle unit testing.</p></div>creynderstag:robotlegs.tenderapp.com,2009-10-18:Comment/33505832010-10-14T12:57:22Z2010-10-14T12:57:22ZSome concerns/questions about Signals<div><p>Cool - there are plenty of us who use it every day and are happy to answer specifics when you get going :)</p></div>Stray