Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

Friday, 23 June 2017

Development : My Top Three Testing Tips

I've said before, and I'll say again, I'm not a fan of Test Driven Development, tests and test frameworks have their place, but they should not; in my opinion; be the driving force behind a projects development stream - even if it does give managers above the dev team a warm fuzzy sense of security, or if it allows blame to be appropriated later, you're a team, work as a team and use tests on a per-developer basis as a tool not as a business rule.

*cough* I do go off topic at the start of posts don't I... *heerrhum*, right... Top Three Automated Testing Tips... From my years of experience...


1. Do not test items which are tested by masses of other developers... I'm talking about when you're using a frame work of library, ensure you are using it correctly certainly, do this at training or with your coding standard, but then do not labour the point by re-testing... Lets take a good example of this, the C++ Standard Library.

The Standard Library contains many collection classes, these classes have iterators within, lets look at a vector:

#include <vector>

std::vector<int> g_SomeNumbers { 1, 3, 5, 7, 9 };

We could iterate over the collection and output it thus:

int g_Sum(0);
for (int i (0); i < g_SomeNumbers.size(); ++i)
{
    g_Sum += g_SomeNumbers[i];
}

However, this is not leveraging the STL properly, you are introducing the need to test the start poing "int i(0);" the end condition "i < g_SomeNumbers.size();" and the iterator "++i", three tests, slowing your system down and complicating your code base.

int g_Sum(0);
-- TEST SUM START
-- TEST i COUNT START
-- TEST RANGE CONDITION LIMIT
for (int i (0); i < g_SomeNumbers.size(); ++i)
{
    -- TEST ITERATION
    g_Sum += g_SomeNumbers[i];
    -- TEST SUM CALCULATION - THE ACTUAL WORK DONE
}
-- REPORT TESTS

Using the iterator, we leverage all the testing of the STL, we remove the need to range test the count variable, we remove the need to test the condition and leave only the step as a test to carry out...

int g_Sum(0);
for (auto i(g_SomeNumbers.cbegin()); i != g_SomeNumbers.cend(); ++i)
{
    g_Sum += (*i);
}

Our code looks a little more alien to oldé timé programmers however, it's far more robust and requires less tests simply because we can trust the STL implementation, if we could not thousands, hundreds of thousand of developers with billions of other lines of code would have noticed the issue, our trivial tests show nothing of gain, so long as we've written the code to a standard which uses the interface correctly...

int g_Sum(0);
-- TEST SUM START
for (auto i(g_SomeNumbers.cbegin()); i != g_SomeNumbers.cend(); ++i)
{
   -- TEST ITERATION
    g_Sum += (*i);
   -- TEST SUM CALCULATION - THE ACTUAL WORK DONE
}
-- REPORT TESTS


2. Do now allow values which have been tested to change unexpectedly... I'm of course talking about "const", which I have covered before on these pages, but constness in programming is key.  The C family of languages allow constness at the variable level, you may notice in the previous point I used a const iterator (with cbegin and cend) as I do not want the loop to change the values within the vector... Constness removes, utterly, the need to perform any tests upon the integrity of your data.

If it's constant, if the access to it is constant, you do not need to test for mutations of the values.

Your coding standard, automated scripts upon source control submissions, and peer review are your key allies in maintaining this discipline, however it's roots stretch back into the system design and anlysis stages of the project, to before code was cut, when you were discussing and layout out the development pathway, you should identify your data consider it constant, lock it down, and only write code allowing access to mutable references of it as and when necessary.

Removing the need to retest mutable calls, removing the need to log when a mutable value is called because you trust the code is key.

In languages, such as python, which do not directly offer constness, you have to build it in, one convention is to declare members of classes with underscores to intimate they are members, I still prefer my "m_" for members and "c_" for constants, therefore my post-repository submit hooks run scripts which check for assigning to, or manipulation of "c_" variables.  Very useful, but identified by the coding standard, enforced by peep review, and therefore removed from the burden of the test phase.


3. Remove foreign code from your base... I'm referring to code in another language, any scripting, any SQL for instance, anything which is not the pure language you are working within should be removed from the inline code.

This may mean a stored procedure to store the physical SQL, rather than inline queries throughout your code, it maybe the shifting of javascript functions to a separate file and their being imported within the header of an HTML page.

But it also includes the words we ourselves use, be that error messages, internationalisation, everything except code comments which is in whatever language you use (English, French etc etc) should be abstracted away and out of your code.

Your ways of working, coding standards, analysis and design have to take this into account, constness plays it's part as well, as does mutability, where ever you move this language to, and whatever form it takes test it a head of time, and then redact that test from your system level tests, trust you did it right based on the abstraction you've performed.  Then avoid burdening your system throughout the remaining development cycle.

One could expand this to say "any in-house libraries you utilise, trust their testing" just as I stated with the STL in my first point, however, I am not talking about code, I am talking about things which are not code, which are uniquely humanly interpretable.

The advantage of removing them and pre-testing the access to them is that you retain one location at which you have an interlink, one place at which a value appears, one place where they all reside and so you leverage easily converting your programs language, you leverage easily correcting a spelling mistake, and all without needing to change your system code; perhaps without needing to even re-release or re-build the software itself (depending on how you link to the lingual elements)

Ultimately reducing the amount of testing required.

Thursday, 3 April 2014

Code Line Numbers

I had a programmer sat with me the other day, he seems a good one too, though I've not seen his actual code.  And he surprised me by peering at my development environment and saying...

"How can you program without line numbers on?"

He was serious, we were exchanging information to ensure I wrote code to meet his coding standards... So why not program with line numbers... Well, I could be annoying and say, I don't write BASIC, so I don't need line numbers... I also don't count K-Locs as a form of reward as to how busy I've been, nor use it as a measure of how productive I am... So really I have to ask myself the opposite, "Why don't you program with line numbers on Xel?"

And the simple answer for me is experience.  Maybe you're different, and you like line numbers, if so "This is not the article you are looking for, move along... Move along"... But to answer for myself, it is simply because I'm human, and the human mind likes to see patterns, it likes to see things and tries it's hardest to impose some semblance of meaning into them.  And for me, if I turn line numbers on then I expect 5 to follow 4, and 4 to have followed 3, and 2 to have come before 3 but after 1... It's an order, and in modern code it is an incorrect order because we should be writing, if not object orientated, then at least functional code.

Functions can be called in any order, objects can be instantiated and used differently by different users, your code itself might do one sequence one way today but a different sequence tomorrow.  The functions themselves still do the same single job with the same input, as per their definition, but code as a whole is no longer linear.

So over time my personal experience has told me to group my code into a simple, but not formal - until this blog post - order, which is "Constructors at the top", then the functions defined "in order of frequency of use", so if you have an update function called all the time in a class, put it at the top, so its easy to spot after your constructors.  Especially in a language like C++ where your constructors can be very brief - or should be very brief, if they're not go rear Scott Meters & Bjarne Stroustrop on the topic!

And then functions are laid out in order of use, least used or single call functions are at the bottom.  I've just come to this pattern, its quite hard to even define it here in words, I suppose I should give code examples, but I'll leave this for another day and come full circle to answer the question "How can you program without line numbers on?"

"Code/Function use is not linear, don't give any indicates to your mind that it is, and if you're going to argue about the contents of one function, your function is too long, break it down into sub-functions which will fit onto the screen as a whole and so you don't need line numbers you can see the whole function in a single pass of the eye".

Thursday, 27 February 2014

HTML5 Animation "Bouncing Balls" Example

Bouncing Circles I've been playing about with some HTML5 canvas drawing/animation examples... You can follow the same tutorials here.

Monday, 17 September 2012

DropBox Coffee Script Conversion


I was just reading coverage of DropBox switching to using some CoffeeScript rather than JavaScript in some of their code base, I was insenced enough with confusion over the coverage to post a comment on the thread... Let me give yout he gist...

The folks over at DropBox have changed to this CoffeeScript code in an effort to "simplify" the code... Least this is one of the major reported reasons for their switching out to JavaScript, they also mention removing bugs... and less size/RAM being used.

Analysing this waffer thing argument however and there's a glaring problem... First of all, CoffeeScript "compiles"* down to JavaScript, so there's nothing CoffeeScript does which you can't yourself achieve in JavaScript... If you end up with smaller code from the output of CoffeeScript then you could simply have written your JavaScript better yourself...

Then there's the argument about CoffeeScript being simpler, and easier, to maintain... I argue that CoffeeScript is just someone deciding that they don't like the C style language formatting of JavaScript and opting for a different style, something which looks rather like HASKEL to me... gah... or Occam... Or a myriad of other languages which don't use braces and semi-colons, you can check it out on their site.

Now consider that most programmers worth their salt know a C style language, its more common and arguably more comprehensible, given JavaScript code they could get by... Given CoffeeScript... its rather alien, take for example the JavaScript for a function:

square = function(x)
{
  return x * x;
};

Now, look at the CoffeeScript...

square = (x) -> x * x

I find the second to be too abstract, square equals an x in brackets (which indicate parameters input) pointing at x times x... What the hell does that actually mean?

Where as the first bit... the square equals a function that takes an x... and that function returns x times x... its a bit less alient, a bit less "haahoo we know sucks to you" in the coding community parlance.

The article says it all, my comment, if it gets published says more...