Showing posts with label Test Driven Development. Show all posts
Showing posts with label Test Driven Development. Show all posts

Saturday, October 20, 2012

Gah! TCP doesn't won't work the way I want :(

Well, I've been having more fun messing around with Node.js and allowing myself to be distracted by interesting problems. The latest of which was triggered by my desire to integrate the BrowserStack beta API for cross browser testing. This is a nice service that will fire up any number of different versions of browsers and point them at a URL that you specify. Integrating this with Testacular and Mocha means that I can run all my browser javascript tests in all browser variants and get the results right back in my shell immediately, without having to run a myriad of browser versions locally :) This even includes mobile platforms :D

So what's the catch?

Well, in order for BrowserStack to connect to my Testacular server it needs to hit a public URL. Unfortunately my development machine is not reachable on a public URL (nor do I want it to be, at least not really public). The solution suggested by BrowserStack was to use a simple service called LocalTunnel. This service provides a client with which you can create an SSH tunnel to a local port that you specify. The service then allocates a random subdomain of localtunnel.com from which it will forward HTTP requests to your local port. Very useful and sounds easy, right? Unfortunately when I tried the client it didn't work and the only clues were leading me into a world of SSH keys, etc.

Hence the distraction. As I probably want to fire up my tunnel and browsers programatically I'm not so fond of relying on command line interfaces and really I want a node module to do it. What's more if I'm going to dig around in secure connections why don't I take the opportunity to expand my knowledge in a direction that I want it expanded. So I decided I would implement my own tunnel service and client solution in node and thus the tls-tunnel package was born.

Early on I figured I didn't want to mess about with generating random sub domains and trying to route based on the sub domain on which a connection was made so instead I decided to assign ports on the server to satisfy client connections. This way whenever a new client connects and requests a tunnel the server will allocate a port from a predefined range of available ports and start listening on that.

My plan was to use a free Heroku or Nodejitsu instance to then deploy my tls-tunnel server when I needed it.

This is where I learnt a hard lesson in the problems of bottom up development. Although I am applying TDD principles I did in fact fail to validate one of my initial assumptions - that I could use multiple ports! Both Heroku and Nodejitsu will only expose one port to your application... this could/should have been a red flag. I realised this early on but plowed ahead anyway thinking that at a later date I could apply a small change to my tunnel and instead use the random subdomain solution to differentiate between tunnels.

So I got my tunnel working using TLS (hence the name) with clients and servers authenticating each other with their own self signed SSL certificates. I was pretty proud of myself for implementing something that was in theory protocol agnostic - I had noticed that other similar solutions were limited to HTTP traffic... this should have been a red flag!

I next turned to the problem of making it all work on one port. Having already learnt quite a bit about the TLS/SSL problem domain I now learned a hard lesson about the TCP domain or more specifically the Node.js net domain.

I had made the assumption that when a raw TCP socket was connected to a server I would be able to read out the domain name that it had used... Wrong!!!

What LocalTunnel is doing is using the HTTP protocol to get the domain name that was used for the connection. GAH!! and what do you know this is the same reason the Heroku and Nodejitsu limit access to a single port. Double GAH!!!

So now I'm left with a choice. My solution can still work but I'm going to have to put it on an Amazon EC2 instance or something (I can get one for free for now). Or I can bite the bullet and implement the same HTTP restriction (boo) and do subdomain based tunnelling.

It's not such a simple choice though. On the one hand it's easy to integrate Heroku and Nodejitsu into my development and testing process (and even share that) as opposed to the hoops I will have to jump through to get it up and running on an EC2 instance. But on the other I don't want to limit my solution to HTTP and I haven't actually verified yet that I can use random subdomains on either service (once bitten, etc).

Perhaps there is a third way though - maybe if I only support one tunnel at a time I can use a single port...

That said, I'm leaning towards the EC2 solution for flexibility ("lean"-ing might be a bad choice of word here though - if you'll excuse the pun ;))

Friday, July 20, 2012

Grunt watch and the Node.js require cache revisited

Still inspired by James Shore's series "Let's Code: Test-Driven Javascript",  I've been continuing with my endeavors to get the Grunt watch stuff working flawlessly(?).

In my last post I mentioned some niggles that were remaining from my previous workaround.
  • The workaround only addresses the Mongoose issue
  • The workaround assumes intimate knowledge of Mongoose
  • Grunt watch still explodes silently when unhandled errors are encountered in tests
    • undefined references
    • nonexistent requires
    • etc.
The good news is that I think I have addressed all of these. In addition to that I've figured out some stuff about how to extend grunt and how to manipulate the Node.js require cache.

First off I thought I'd take a look at Mocha to see if it handled things better. After all Mocha also has a watch function.
  • Mocha watch does not explode on undefined references (which is nice)
  • Mocha watch does still explode on nonexistent requires (actually I didn't find this out till much later on when integrating with grunt)
  • Mocha watch still failed to handle my Mongoose issue
  • Unfortunately Mocha watch doesn't integrate with JSHint and actually I'd quite like to lint my code on file changes too
So despite only having a small advantage in not falling over so much I thought Mocha showed more promise than NodeUnit and as James noted it is much more active on GitHub. In fact it's under the same banner as Express and Jade which are definitely very popular and well maintained frameworks for Node.js.

Next thing was to integrate Mocha with Grunt so that i can use the Grunt watch function to both lint and run tests on file changes.

The nice thing about writing my own task to run Mocha instead of NodeUnit is that it was then quite easy to fix the issue of exploding on nonexistent requires... It just needed a try/catch around the mocha.run call. In retrospect I could probably have added this to the existing NodeUnit task but by the time I got to this point, I'd already ported all my tests to Mocha.

[A short interlude on Mocha and Should...]

James noted in his videos that Mocha is targeted as a BDD test framework and as such he is not so keen on it's verbosity. I can see what he means but, to be honest, I don't find it much of an issue and in fact quite like it, so for a while at least, I think i'll stick with it.

I also tried the should.js assert library that provides an interesting take on asserts by making them a bit more natural language like. Things like: thing.should.have.property(things).with.length(5);

On first take I thought cool and went full steam ahead in making all my asserts like this. Currently though I'm not sure I like it.

For one, I keep thinking that I should be able to write something in a natural way but find that it's not really supported - it kinda feels like I'm being teased. This will lessen I guess as I really learn the idioms.

A more annoying problem though is related to the way Javascript handles types and comparisons. I keep finding comparisons that i think should work and don't and then comparisons that I think shouldn't work and do! I think this is made worse by hiding the comparisons inside assert functions. As a result I'm starting to come to the opinion that not only is the should framework more trouble than it's worth but in fact any assert framework that hides comparison logic is not such a good idea to use in tests in Javascript. This includes very standard things like: assert.equal(object1, object2);

I may revert to just a single check function that will better reflect how comparisons would actually be written in production code. Ie: assert(conditionalCodeThatResolvesToTrueOrFalse);

[...interlude over]

So there I have it, I can now run my tests as files change and rely on the watch task to keep going no matter what happens (so far!). Just the mongoose problems to resolve then, and actually I added another.
  • If a unit test beforeEach function falls over then the after functions are not run
    • This means that as I open a database connection in before and close it in after, when I get such an error I then continue to get failures when files change due to not being able to open the database anymore (it's already open)
    • Not as serious as the silent failures as at least the watch process keeps pinging me and I can restart it. But still a little annoying
This new issue got me thinking again about the require cache. My previous investigations here had proven fruitless but then, perhaps I had been led astray by some dubious comments on StackOverflow. Beware, this code does not work:

for (var key in Object.keys(require.cache)) {delete require.cache[key];}

So now I was thinking about the Mongoose module.
  • The problem isn't that the changed module is still in cache
  • The problem is that the Mongoose module is still in cache
  • In fact the problem is that any modules are still in cache
  • I must clear the cache completely before running my tests!
    • Actually I had tried this and it didn't seem to work
    • However I had tried it in my tests themselves, now I could try it in my new grunt task :)
      • I had already needed to add code that dropped all my own files from cache to make things work. It made sense to drop the rest too when I come to think about it.
So i fixed the code above:

for (var key in require.cache) {delete require.cache[key];}

Tidied up my mocha task adding support for options and this is what I have in a new module...


To use this I dropped it in a grunt tasks directory and updated my grunt.js file...


Note that the call to loadTasks takes the directory name. Also note that I overrode the built in NodeUnit test task and that the options to pass into mocha are given in the mocha config property.

So that's it I no longer have to use my Mongoose workaround as the Mongoose module is cleaned up along with everything else before I run the tests :)

I hope this will save me from similar gotchas in other modules too, but I guess I'll just have to code and find out :D

Wednesday, July 18, 2012

NodeUnit, Mongoose and Grunt watch

Edit: Although interesting to me as a history to my Node.js testing issues, this article is now pretty much superseded by this one which better addresses all of the below problems

Now that James Shore's "Test Driven Javascript" series has kicked off I've been integrating unit tests into the 5Live hangout project. This has, for the most part, been simpler than I expected. NodeUnit is pretty easy to use and from one of the comment threads I have been introduced to Grunt which allows me to tie all my lint tasks and unit tests into a single automated script (James has been doing this himself in Jake but I figured I would give Grunt a try as it does some of the 'grunt' work for me :)) .

Like I said, for the most part this has all been going swimmingly. One of the nice features of Grunt that I discovered is the watch task. This allows me to watch a list of files and when they change, automagically kick off my lint tasks and unit tests - very nice :D

There are some problems though. My application uses Mongoose to interact with a MongoDB database. As such I follow the standard mongoose pattern of using a singleton and defining my model schemas like this...



As I'm doing TDD I actually start off with something like this in a separate test file...



That's all hunkydory. I can run the tests and they pass. I can kick off grunt watch and leave it running while I start editing my files. Let's see what happens when I change my test, thusly...



As expected grunt watch pings me to let me know that my test has failed :)

So I go back to my model and update the greeting function...



Gah, grunt watch pings me again to say that my test still fails. Puzzlement abounds!

If I stop grunt watch and run the tests manually they pass! So what's going on?

Well I wasted a lot of time messing around with the require.cache object, as I figured it was something to do with Node.js module caching, but that wasn't it at all. Either NodeUnit or Grunt is smart enough to remove the changed files from the module cache (I think it must be Grunt that does this but I didn't check).

Eventually I realised that it was the mongoose singleton that was causing the problem. After all this only happened with my mongoose model tests. As the mongoose singleton persists between test runs it doesn't matter that I change the methods on my models, the old versions also persist.

Again I tried a number of workarounds but so far the best seems to be the following.

First I created a wrapper for the mongoose singleton which allows me to reset the schemas...



Next I integrated this wrapper into my tests (only the tests, i still use the the mongoose singleton directly in the model implementations)...



So why do I prefer this solution and what else did I try?

Well I also had another workaround which fixed the problems with method updates.
  • Instead of using Schema.methods to assign methods I used Model.prototype
  • Instead of using Schema.statics to assign static methods I just assigned them to the Model directly
Why didn't I like this?
  • This solution meant a little rejigging of the code to what seemed like a non standard pattern in the actual implementations
  • This did not fix a similar problem with updating the actual Schema - ie. adding or removing fields
I still don't much like my eventual workaround as...
  • it depends on knowledge of the the internals of Mongoose (which might change)
But at least it's contained in my tests and seems to work for all changes in the model.

However, even with this workaround in place I'm still  not fully happy with the way grunt watch works.
  • Annoyingly, it exits on a number of test failures particularly when things are not yet defined. This happens a lot when doing TDD, it's how we write failing tests.
    • When it does exit it doesn't actually ping me. As such I have to keep looking to see if it stopped (If i have to do this all the time, it occurs to me that I may as well not use it and instead run my tests manually)
  • I'm now just waiting for the next gotcha as I only worked around a problem with Mongoose.
    • It seems to me quite likely that there will be other libraries that follow similar internal patterns and they are likely to trip me up in the same way
I have a solution to suggest though...
  • Spawn a new Node.js process at least for every grunt watch event if not for every NodeUnit test
    • Wouldn't this fix the problem once and for all?

Wednesday, June 27, 2012

OOOCode - Part 2

Phew, a lot has happened since my last post on this subject. After much wrangling with the C preprocessor I have a working pattern which I'm mostly happy with. It currently includes support for the following...

  • Classes
  • Private data
  • Public methods
  • Private methods
  • Multiple interfaces
  • A unit test framework
  • Some eclipse file templates

Still to do (in no particular order)...

  • Documentation
  • Performance profiling
  • Exception handling
  • Improve unit test automation
  • Eclipse wizards

Things that I'm not quite sure about...

  • Not sure if I really needed to implement the unit test stuff as classes and interfaces but it has an elegance
  • Don't much like having multiple calling conventions for public methods, private methods and interface methods
  • No support for inheritance - is it really needed anyway?
  • No support for up casting and figuring out what type something is at run time - this may become more of an issue when thinking about exception handling
  • Currently only support a single constructor

This state can be found on GitHub here

So how does it look right now (after all there is no documentation ;))

Create an application that runs unit tests

After generating your own application as described in OOOCode - Part 1 copy in the OOOCode/src/OOOCode directory from the above github project and add it and its subdirectories to the OpenTV options include paths.

Then create a Main.c as below...

The above code achieves the following...

  • Records the memory available at start up
  • Creates a debug output object using the OOOConstruct macro
    • In this case an OOODebug class is used instead of direct calls to O_debug as in tests for the unit test classes themselves it is necessary to use mock objects
  • Creates a debug reporter object
    • Unit test reports need to go somewhere, this class dumps them to debug output
    • The debug instance is cast to an IDebug interface using the OOOCast macro, in this way it is possible to pass in a mock object when needed
  • Calls the OOOUnitTestsRun method passing in the reporter to run the tests
    • The debug reporter is cast to an IReporter interface using the OOOCast macro, this will allow the unit test framework to be extended later with different reporter objects (eg. over HTTP, etc)
  • Then the instantiated objects are destroyed using the OOODestroy macro and the memory is checked to ensure that the tests and the unit test framework used did not leak
  • The last part (while loop) just ensures that the VSTB does not exit so we can see the test report in the debug output

So there are some key concepts introduced here...

  • OOOConstruct - use this to construct an instance of a class, the first parameter is the class name, additional parameters are passed into the constructor as arguments
  • OOOCast - use this to cast an instance of a class to an interface, the first parameter is the interface name, the second parameter is the class instance
  • OOODestroy - use this to destroy an instance of a class and free it's memory, the only argument is the class instance

However, this will not yet compile. The function OOOUnitTestsRun is a special function that is generated by the OOOUnitTestsRun.h header file using xmacros. It generates an array of tests to run and runs them based on the contents of another header file: OOOTests.h

This initial OOOTests.h is empty and so this application does not yet run any tests. Now the application can be compiled (assuming that the OOOCode source has been added to the include paths).

NB. The OOOTests.h file does not have an include guard and this is deliberate. An include guard would prevent the xmacros that use it from working. For more details on the xmacro pattern see this drdobbs article

Adding a test for MyClass

First update OOOTests.h...

Once again this will not compile, but hey, we're doing test driven development.

Add the MyClass.Test.h header...

Still this will not compile, but note that the OOOTest macro call does not have a semicolon on the end - this is important. This just declares the test it does not yet compile because the test has not been implemented. Other tests can be declared with other names by adding further OOOTest calls (without semicolons)

Add the MyClass.Test.c file...

Now it gets a little bit more interesting and in fact should compile and run again. When it is run this code will print the "MyClass test" string to the debug in an xml test report format signifying that it is just information. The important concepts that we now have are...

  • Declare tests with calls to OOOTest in unguarded headers that are included in OOOTests.h
  • Implement tests using the OOOTest macro as defined in OOOUnitTestDefines.h so that they look like functions
  • We can ouput information to the test report using the OOOInfo macro (this is actually a variadic macro that behaves like printf). Two other similar macros are also available in test implementations...
    • OOOWarning - adds a warning to the test report
    • OOOError - adds an error to the test report

Adding MyClass

We are going to add a class that takes an integer in the constructor and exports a method to retrieve that integer. So lets first write some more of the test. We update MyClass.Test.c as follows...

Again this will not compile but we can see how we want our class to behave...

  • We include the class header (does not yet exist)
  • We construct an instance of the class
  • We check the retrieval of the integer constructor parameter
  • We destroy the instance of the class

The key concepts are...

  • The memory allocated in a test must be freed in the test, the unit test framework does check for memory anomalies and adds them to the test report
  • Public methods are called with the OOOCall macro, the first argument is the instance, the second argument is the method name, additional arguments would be the parameters for the method
  • OOOCheck is used to test a condition that must be true for the test to pass, it can be called as many times as you like but if the condition resolves to FALSE then an error entry will be added to the test report along with the file, line and condition that failed, etc.

Add MyClass.h...

Now things are getting really interesting. Still this will not compile as we do not have an implementation for MyClass but lets go through what's happening here in the header...

  • We have an include guard - that's fine here :)
  • The OOCode.h header is included to enable all the OOOCode goodness ;)
  • The name of the class is #defined as OOOClass - this is used inside other macros as the class name and simplifies those macro calls
  • The class is declared using the OOODeclare macro, it takes the constructor arguments as parameters
  • A list of implemented interfaces is given using the OOOImplements block, this must be present even if it is empty as in this case
  • A list of public methods is given using the OOOExports block, in this case one method is exported using OOOExport
  • The declare block is closed and importantly OOOClass is #undef'd so that other classes can be declared

Let's go through those macro calls in a bit more detail...

  • OOODeclare - actually declares the type and the constructor hence the addition of the constructor arguments
  • OOOImplements - starts the structure defining the public interfaces avialable (OOOImplement will be detailed later)
  • OOOImplement - finalizes the interfaces structure
  • OOOExports - starts the vtable structure providing access to public methods
  • OOOExport - adds a public method to the vtable, the first argument is the return type, the second argument is the name of the method, any further arguments will be the parameters for the method (in this case there are none)
  • OOOExportsEnd - finalizes the vtable structure
  • OOODeclareEnd - this finalizes everything and defines a public structure used to access the public methods and interfaces

Now we're also ready to add the implementation, so create the following MyClass.c file...

So what's this all about then...

  • Include the MyClass.h header
  • #define OOOClass to the name of the class, again this is so that other macro calls can use it and their interfaces are thus simplified (it would be nice if macros could define other macros internally, but hey ho...)
  • Declare the private data fields using OOOPrivateData - just one integer field
  • Implement the destructor function with OOODestructor - in this case it is empty as no additional memory is allocated when constructing objects of this class
  • Implement a method using OOOMethod - this one just returns the integer field accessed through a call to the OOOF macro
  • Implement the constructor using OOOConstructor - in the constructor it is also necessary to map any internal functions to external methods and interfaces, in this case...
    • OOOMapMethods is used to open a list methods to map to the exported vtable
    • OOOMethodMapping is used to map the getMyField method to the first entry in the vtable - the compiler will pick up any type incompatibilities here
    • The mapping is closed with OOOMapMethodsEnd
    • Lastly the constructor assigns the nMyField parameter to the nMyField private data entry (again using the OOOF accessor macro)

Again let's look at these new macros...

  • OOOPrivateData - starts a new private data structure, this should only appear once
  • OOOPrivateDataEnd - closes the private data structure, fields in the structure should be placed between these 2 macros in the same format you would use for a struct (it is a struct!)
  • OOODestructor - this starts the destructor method, destructors take no additional arguments, this should only appear once
  • OOODestructorEnd - this ends the destructor method, it actually also frees the class instance which is why you don't have to do it yourself. The curly braces between these 2 macro calls in this case a re purely a matter of style and optional, they would only be required if it were necessary to declare any local variables in the destructor method. I use them anyway because it makes the implementation look more like a standard C method (a bit)
  • OOOMethod - this starts a method implementation, the first argument is the return type, the second is the method name, any additional arguments will be passed into the method. The method is effectively private until it is mapped to the class or an interface vtable (the macro declares it static)
  • OOOMethodEnd - this closes the method implementation, again the curly braces are mostly optional
  • OOOConstructor - this starts the constructor implementation, it should appear only once. The arguments are the constructor parameters
  • OOOMapMethods - this starts the class vtable mapping
  • OOOMethodMapping - this maps a method to an entry in the class vtable, the only parameter is the method name - this is the private method name as defined in the call to OOOMethod, it does not have to match the exported method name in the vtable defined in the header. It is important to add the methods to the mapping in the same order that they are added to the vtable in the header using calls to OOOExport
  • OOOMapMethodsEnd - this closes the vtable mapping
  • OOOConstructorEnd - this closes the constructor implementation
  • OOOF - this macro accesses the private fields of the current class instance, the only argument is the name of the field. It is not possible to access fields of instances of other classes but later we will see how to access fields of other instances of the same class

Adding IMyInterface

We will now add an interface that defines a single method that returns an integer. Again let's start with the test and update MyClass.Test.c as follows...

Only a small change but again this will not compile...

  • We added a new check, casting the instance to IMyInterface and calling the getData interface method using the OOOICall calling convention - in the test I have assumed that getData will be mapped to retrieving the constructor parameter

Only one new macro has been introduced here...

  • OOOICall - this macro must be used when calling methods on interface instances, it is much the same as OOOCall in that the first argument is the interface instance, the second argument is the interface method name and any additional arguments are passed through as parameters to the implementation

To make this compile we will have to add IMyInterface.h and update MyClass to implement the interface...

This is pretty similar to the pattern used to declare the class...

  • There is an include guard
  • OOOCode.h is included
  • This time we specify the interface name in a #define called OOOInterface
  • The interface vtable is then started with a call to the OOOVirtuals macro
  • Methods are added to the vtable using calls to the OOOVirtual macro
  • The vtable is then closed and OOOInterface is #undef'd so that other interfaces can be declared

So the new macros are...

  • OOOVirtuals - starts the interface vtable
  • OOOVirtual - declares a method entry in the vtable, the first argument will be the return type, the second argument is the method name and any additional arguments will be the parameters for the method. Any method implementing this virtual method will have to have the same signature and the compiler will check
  • OOOVirtualsEnd - closes the interface vtable

This still won't compile so next we update MyClass.h...

Again a small change...

  • The interface header has been added
  • An OOOImplement call has been added to the OOOImplements block to add the interface to the declaration

Just one new macro then...

  • OOOImplement - this adds the interface to the interface table, the only argument is the name of the interface

This will compile but the test will fail. In fact the test should crash with a NULL pointer exception as the method has neither been implemented or mapped to the interface. We need to update MyClass.c too...

Now the code will both compile and the tests will run successfully! (assuming I transcribed everything correctly).

There are 2 additions here...

  • The method has been implemented as getData and this method just calls the other method using the private method calling convention, OOOC
  • The interface vtable has been mapped in the constructor
    • The interface name is given in the OOOInterface #define to simplify the other macro calls
    • The interface vtable mapping is started with a call to OOOMapVirtuals
    • The getData method is mapped using a call to the OOOVirtualMapping macro
    • The mapping is closed with a call to OOOMapVirtualsEnd and OOOInterface is undef'd so that other interfaces can be mapped

So the new macros we have used are...

  • OOOC - this macro accesses the private methods of the current class instance, the first argument is the name of the method and any additional arguments are passed through as parameters to the method. It is not possible to access private methods of instances of other classes but later we will see how to access methods of other instances of the same class
  • OOOMapVirtuals - this starts the interface vtable mapping
  • OOOVirtualMapping - this maps a method to an entry in the interface vtable, the only parameter is the method name - this is the private method name as defined in the call to OOOMethod, it does not have to match the exported method name in the vtable defined in the interface header. It is important to add the methods to the mapping in the same order that they are added to the vtable in the interface header using calls to OOOVirtual
  • OOOMapVirtualsEnd - this closes the interface vtable mapping

Adding copy and isEqual methods

As a final example and to round out the macro examples let's see how we can add additional methods to copy and compare instances of MyClass. Of course, we start with a test so let's update MyClass.Test.c...

The following changes were made...

  • A new instance of MyClass, pMyClassCopy, is generated through a call to a new copy method
  • We check that the new copy is equal to the original
  • We check that the new copy returns the same value from getMyField
  • We check that the copy method didn't cheat and that the copy is a different instance (pointer address)
  • We remember to clean up the new instance too

Once again our code does not compile, but that's ok. We need to update MyClass.h to export the new methods...

This will now compile but, as with the interface implementation, the test will crash when it gets to the copy call as the method has not been implemented and mapped in the vtable. Anyway let's see what we've done...

  • Two new calls have been made to OOOExport to export the copy and isEqual methods

Now we implement and map the methods in MyClass.c...

Yay, sucess! The code compiles, runs and the tests pass. We added 2 new methods and mapped them so what's new in this...

  • In the compare method we used a new macro, OOOPCall, this is more efficient than OOOCall and can also be used to access unmapped methods in a class. The first argument is the class instance, the second is the method name and any additional arguments will be passed into the method. In this case OOOC could not be used as we wanted to call a method on another instance
  • Notice that the additional mappings in OOOMapMethods are preceded by commas - this is because they result in static initialiser elements in a structure. The same applied to the virtual mappings if there are more than one.

So what haven't we seen? Well, two additional things spring to mind...

  • It is also possible to access fields on other instances of a class. This is achieved through calls to OOOField, like OOOPCall this can only be used in the class implementation and the first parameter will be the instance, the second parameter is the field name. We could have used this in place of OOOPCall above but it is a matter of style to use the accessor method instead (performance optimisations could dictate otherwise though)
  • If it is necessary to access the current instance (perhaps to return from a method or pass into another method) then it is always available in the methods, constructor and destructor through the OOOThis pointer

So that's it. Although this will all probably change in the next 5 minutes. If you're interested then keep an eye on this blog and the GitHub repository.

Friday, June 15, 2012

Required watching!


http://jamesshore.com/Blog/Lets-Play/

Well it might be if it weren't 197 episodes and counting but this series of videos illustrating test driven development (TDD) in Java and Eclipse are really excellent. I'm currently up to episode 25 (since yesterday... addicted!) and already I have learnt so much about:

  • writing tests up front
  • emergent design
  • AND just how magical eclipse is when it comes to generating code and refactoring in Java

I really recommend watching some of these. It starts with a completely blank application so I would go from there.

I really want some of these IDE features in the OCode development we do too. And I can see that there may be some mileage in that.

Now i can't wait for James' new series that I gladly helped fund on Kickstarter.

http://www.letscodejavascript.com/

2 things that have got me excited recently in one package - TDD and server side Javascript... Yay, Node.js!