Outsourcing and Quality…
Yesterday night I’ve received an interesting comment on my PHP@INDIA posting. After reading I’ve decided that this deserves a posting to answer it thoroughly.
The comment was
The poster who made this statement doesn’t explain to you that India-based workers can only speak about 60% english.
he doesn’t explain that these same developers use BEGINNER LEVEL coding techniques that render your site open to almost the most grade-school level of attacks.
he doesn’t explain to you that these same developers don’t give a damn about you, or your project.
he doesn’t explain to you that their answers to questions are from monitors on their screen, and should you have an advanced-level technical question they are NOT going to be able to answer for you.
And he also didn’t explain that you GET what you PAY for. You pay for garbage in India, expect garbage as a product. You pay good in America for a product, expect the best as a product.
The commentor is right in his statements. Actually talking about Quality in outsourcing you need to take care that the quality is good enough for you. It would be simply very dumb to rely on any developer - check it personally! I’ve made the same experience 10 years ago like my anonymous commentor, but I had to understand that things changed and that it is possible now to get better quality. But as always - you need the right partner.
After reading my posting again I’ve realized that I need to clearify a few things. Outsourcing (in PHP area!) is never about saving money. Having good people inhouse or around the corner will help your project a lot. Outsourcing is about scaling. If you do have any tasks which need to be scaled, like developing the same stuff again and again, editing pictures, running any process against something which need to be repeateded over and over then you should think about offshoring.
I state that it’s very difficult to scale your team from 5 to 15 inhouse fast - and this is possible in india. Simply because there are many indians.
A few rules need to be applied to choose the right partner:
- Do never ever give your core technology to any outsourcer somewhere on this planet. You need to have full control over your technology. Otherwise the risk of beeing ripped off is very high.
- Choose your partner thorougly. Check the references and call them to doublecheck.
- Be aware of your expectations. You will need a few months before the project will run by itself.
- if you do not put in energy, knowhow and your personal sweat it won’t work.
Follow these rules and your outsourcing project will be successful.
To come to an end - yes, also in india you get what you pay for. This is valid anywhere on the planet. Pay your developers well and you will get good quality. And for sure you can not judge over all people in a country - there are good and bad developers all over the planet. Even though it is hard to believe - just beeing american doesn’t make you a good developer - and vice versa - beeing indian doesn’t make you a bad developer.
PHP@INDIA ?
Did you ever wonder if these Millions of Indian developer we often read about are capabale of doing good in PHP? I did. And I tried.
Back in my past (*cough* - hitting 40 soon…) I’ve outsourced parts of my jobs to many countries, starting with a company in Prague/Czech Republic together with my friend Matthew, and moving later on to lithuania where I still run (together with my mate wolfgang) a development office with a total of 60 developers, coding for various projects like swoodoo or oxid.
During these nearly 25 years I did work for sure in a few projects where coding was outsourced to india. My experience in the past was not really good. The classical project in india was:
- huge
- really huge
- f.. huge
did I mention huge?
Why is that so? Well - the average indian developer is (was!) teached to work as some sort of coding-ant. Don’t think, just do what you gotta do (futurama). Thus this ended in a culture where you need to write a very detailed spec ( thousands of pages) and hand this over to your “ant” farm where 500-1000 developers code what you told them todo. Still you need to check personally the quality as (in the past!) the indian culture does not support being honest in case of problems as this is considered rude. Ah - being rude… tell me.. the ones out there who had the pleasure… to meet me in person know that I am a really honest person thus it is very easy that myself is been taken as rude….
So this was the past - 12 years ago. In 2008 I’ve started a second try - and guess what ? It worked! After investigating the right partner via my personal network I’ve started to work with Anantara. A small company, with very bright minds in management, reliable and trustworthy. Nothing what you can expect anywhere on the planet.
Anantara was working in the usual areas - Java and .NET but not very much in PHP. So I helped them a bit to kickstart a fresh PHP team - and they kept their promises and delivered a good working team. To my pleasure they realized that the PHP area is a very interesting market to them, so they decided to put a lot of energy in this area - sic! Times are really changing, especially now when we talk about the crisis - it matters what you pay for your software, and PHP is simply a lot of cheaper (aka faster) developed compared to .NET and java.
Don’t get me wrong - outsourcing is always difficult and by far less efficient compared to in-house developers. You always have to bridge a cultural/business gap which is most likely there. You can’t expect that some people anywhere on the planet earth understand your business needs without teaching them thoroughly.
But - in the past I had much worse experiences - and now I’ve really enjoyed to work with Anantara the last year. Our project stopped now, as it ended succesfully, but I am definitly looking forward to work with these guys in future again. From a PHP skill level I would estimate that there is average know how - which is better than many code I’ve seen in the last years developed in germany. Needless to say that they do agile development - what else…;)
So - if you are interested in contacting them or you do have any other question concerning outsourcing - feel free to contact me. I’ve decided to support Anantara a bit as I really do like them - and no - I am not paid, nor am I a shareholder there. Most likely they will pay me a beer (or two…)
7 things….
Already a few days ago I got tagged by Manuel Pichler and Gaylord Aulke. I could not post as I was really sick the last two weeks. Today is the first day where I see light at the end of the tunnel and I feel good enough to answer the questions.
So you really want to know seven things about me ? Well - you asked for it
1. I earned my first money by creating a blackmarket in secondary school for sexual explicit material, which I bought cheap and sold expensive. This was one of the reasons I had to leave this school.
2. My first love was named Commodore 64. I teached myself Assembler and started to rip off music from games, creating my own demos.
3. My holidays are usually spent in croatia as my beloved wife was born there.
4. I work with a bunch of developers in lithuania, and hey - these guys (and girls!) are really good.
5. Recently I donated my book collection of > 2500 science fiction and fantasy books to a shop where handicapped sell the books to life from that.
6. Although I was born in bavaria my limit are 3 litres of beer, after that I am really really drunk.
7. I can’t stand cold weather - I feel well at an average of 26+ degrees. Oh, do you remember 4. ? In .lt the winters are really really REALLY cold and I hate it.
So - now my turn. Not so easy. I think nearly everybody who I know was already tagged, therefore - sorry about that - I need to tag a bunch of german people who I think are not yet tagged by this meme.
Here we go:
1. Nils Langner for teaching PHP ![]()
2. Thorsten Rinne just to remember him that he still ows me a self cooked thai menu.
3. Xenjo because I am curious what he would write….
4. Ralf Eggert to support his upcoming Zend Framework book (in german only)
5. Christopher Kunz who runs partly my servers for swoodoo and takes care about themeven from holiday. Thanks Chris !
6. Tomas Liubinas one of the .lt developers I mentioned and actually he was part of the team who won in plat-forms contest.
7. Max Horvath for… hmm… I still wait for the pics
These are the rules apparently:
Link your original tagger(s), and list these rules on your blog.
Share seven facts about yourself in the post - some random, some weird.
Tag seven people at the end of your post by leaving their names and the links to their blogs.
Let them know they’ve been tagged by leaving a comment on their blogs and/or Twitter.
Tadelloses Hören wird garantiert…
Wenn ich also bei fastbooking mein Hotel buche, dann kann ich besser hören ?
2 Ziele motivieren unsere Arbeit:
-, um Sie das genauste und verschiedenste Angebot möglich anzubieten
- um Sie eine Unterstützung und ein tadelloses Hören zu garantieren
Find ich super! Was ich da wohl höre?
Entschlüsselt ?
Ohne Worte.
BravoFly verwendet das neueste sichere Zahlungssystem SSL. Sobald Ihre Buchung bestätigt ist, werden Ihre Kreditkartenangaben übertragen und nach SSL (Secure Socket Layer) Standards in vertraulichem Modus ENTSCHLÜSSELT und für die Autorisierung verbunden.
Ach ja - die Grossbuchstaben für “ENTSCHLÜSSELT” sind Original und nicht von mir eingefügt.
IPC08 - This was 2008, looking forward to 2009
Again a year passed by and the International PHP Conference closed his doors. I finally made it home, slept 14 hours and now I feel not like a zombie any more. This year was quite exhausting for me as I had to stay to full length - from Sunday Evening till Friday Evening. And - as usual - the evenings were the most interesting part. Everyday (a bit) drunken… I think I need to train more to make a better position next year
As always “la famiglia” showed up so I met all the usual suspects starting with the guys (and girls) from gayflowr Mayflower to Tobias Schlitt and Kore which whom I had as usual a lot of fun till the very well known Derick Rethans and Sebastian Bergmann. Ah, not to forget Max, Markus and Gaylord
Over a whisky Markus and myself discovered that the world is really small. We’ve never met, but one guy working for me on the very old times brought him into touch with PHP.
Interesting for me was also that I got into touch with a few really nice guys who I somehow missed to meet in the past. Pierre is a good example. I don’t know how I could miss to meet him
I think we fit together as we might both start the PHP Senior Group - or maybe we build it alone ? Furthermore I’ve met Ralf and Nils who attenden PHP Conference even tough he seem to hate it
Having beer with them together on the “late oktoberfest” was a pleasure.
So - enough about the party ( even tough I consider this the main part on any conference as there you get the real good answers and contacts ) - which talks I held this time ?
Together with Thorsten ( the ‘womanizer’ with the most famous blue eyes) we had a full day workshop on “Theory and practice – migrating your legacy code into our modern test driven development world”. For me very interesting was the even tough we expected that everybody who attended already uses TDD - this was not true so we had to change the workshop a bit on the fly and went back to the basics.
On Tuesday I continued giving a talk about Monitoring your business. I was not quite sure what the attendees expected but it seems that I could manage to satisfy them.
Finally I’ve agreed to talk on the last “Enterprise” Day about “Agile Softwareentwicklung bei Geschäftsanwendungen” - sorry about the german, but the whole day was in german. And many thanks to Periklis who gave me the very interesting figures in it about the performance gain a team can get using agile methods.
On Friday I also had to hop in for Bjoern who unfortunately got sick
- hope you will be better soon Bjoern! It is quite challenging to create a talk in 40 minutes out of the nothing but with the help of Thorsten I made it. And so I’ve talked a bit about “So gelingt der Umstieg von PHP4 auf PHP5: Erneuerung von Geschäftsanwendungen unter Qualitätsaspekten”
I think this was it - at least everything what I can remember
- if I met you and forgot to mention you, please kick ping me.
IPC 2008: Impressions
In the speaker shuttle to the (far away) hotel:
“Stop moving your knees!”
“This is not my knee…”
“OH MY GOD!”
Refactoring your legacy code - Part four: Fixture this!
Another day in paradise. The right time to continue with our small series about refactoring. Today Tomas and me will talk a bit about the right (and wrong) way of preparing your data for the tests - the so called “Fixtures”. If you will read in the text the context “we” then Tomas wrote this part about his experience with the OXID refactoring.
Remember - we learned how to test simple 2×2 functions but when we tried to test more complex ones initialy we felt like stalled with no or negative progress. We tried to identify what is the difference between simple functions returning a value from supplied parameters and the real life ones.
The problem with those functions is that they depend in most cases on your application state (script globals, config vars, session vars, object state, existing data etc..).
As already shown in the previous postings we are able to separate all the code into a few abstraction layers (db access, fetching config vars,..) and we did that, but finally we still wanted to test in a simple way the high-level functions. Eg. createOrderFromBasket()->saveOrder()->loadOrder() flow. Lets identify the issues preventing us from simply testing these functions and see the way how OXID handled them.
Time consuming fixture creation:
It is quite easy and fast to prepare a small data set for tests, but when you try to test a bit more complex functions like the calculation of values in a shopping basket, then you have to prepare the full basket and define all the needed values (products, amounts, vat… ). And if you have to do this for every test, this is a pretty boring task.
OXID decided to solve this issue by creating a test database filled with all the common data: users, orders, various combination’s of products, discounts etc. For each test where we needed this data we created on the fly fixtures out of this database - some sort of “fixture” generator with a static source (our database). This helped a lot in speeding up fixture creation. I’ve heard some opinions and complaints that our big demo data is a big NO, not a really valid “fixture” and you should prepare fixtures for every test separately, but why not to consider our test data as one fixture - only bigger? Leave us a comment if you think different!
Actually the way described above violate the theory behind TDD. In the swoodoo team we do it a bit different - but still I want to share this with you, as it’s a real world example and - not to forget - a very successful one.
Test data is altered via another test:
And here we have the next problem. When you have one big test data chunk, it gets altered by other tests. One of the (very wrong) ways would be adjusting tests, depending on which order they are run. But it’s clear you will reach a dead end very soon. Do not even try this. Wrong!
How did OXID solve this? First of all we created a rule: use test data for reading relaxed (actually the nature of our business logic is that it is “read data” oriented) and - if we need to change test data for test – make sure we change it back on tearDown(). This is still dangerous as one failed test may result of other test failing. Tracking this kind of failures is most difficult task. So additionally we use a small script which is run after each test (test class), which diffs existing db with initial and restores it.
Actually the much better way is to create the fixtures each time manually with tools like yaml. This way is the correct way and it can be solved also without too much work if you create yourself a generator for yaml. Doing so will avoid many problems like the ones described above. On the other hand - this is pure theory. And refactoring an existing application is something totally different than creating a new one with the latest state of the art technology.
Refactoring your legacy code - Part Three: View me!
And there we are again - today we will take a deeper look into the views.
It is important to decide which classes are critical to test and which classes only deal with retrieving information. The MVC pattern is the answer. It separates logic from presentation. View classes only “reroute” the information and Controller classes host all the logic.
Decoupling Models from the Views is vital for your tests. For the model you need to have nice unit tests. The Views should be tested by acceptance tests. Some people do also run unit tests on the Views - it is possible - but my personal opinion on this issue is that you really should try to avoid logic in the view and then it’s sufficient to test them via selenium tests.
This is why we created a new rule in effect – no logics in view classes, just getters and setters for controllers and super global wrappers.
Let me give you a good hint: do never ever use the accessor methods for the super globals from the model classes. Let it be $REQUEST, $COOKIES or even $SESSION. All these parameter should be collected in the view and passed on to the model. Doing so gives you the chance to have small, clear and decoupled functions and also your tests can be done very easy.
Let’s see how this could look like before:
class displayUserDetails() { /** * Processes input and sends user first name, last name to display; */ function show() { global $dbLink; global $templateEngine; $itemId = (int) $_REQUEST['user_id']; $firstName = $dbLink->getOne("select first_name from users where id = $itemId"); $lastName = $dbLink->getOne("select last_name from users where id = $itemId"); $templateEngine->addTemplateVar('firstName', $firstName); $templateEngine->addTemplateVar('lastName', $lastName); $templateEngine->display(); } }
and after refactoring you should get something similar:
/** * A view class responsible for displaying user details. */ class userView() { /** * Loads user object and sends first name, last name to display */ public function show() { $userId = $this->_inputProcessor->getParameter("user_id"); $this->templateEngine->addTemplateVar('user', $this->model->loadUser(userId)); $this->templateEngine->display(); } } /** * And the corresponding model */ class userModel() { public function loadUser($userId) { $user = new User( $userId ); return array( 'firstName' => $user->getFirstName(), 'lastName' => $user->getLastName()); } }
And - as usual thanks to Tomas who provided this time the examples.
Refactoring your legacy code - Part Two: Global Problems ?
Today we want to address a global problem. No - not the global warming up - instead the misuse of global scope in variables and functions. This is a followup to my previous posting. And again (as every posting in this series) some advertisement for our talk at the phpconference.
Legacy Applications are often done in PHP4. Which means no really object orientation. All class variables are public - and this is how they are used. Over the time many members are set/get in different places.
If you start writing a test - you need to make sure that you only test specific functions. All subsequent calls, data etc. need to be stubbed == faked.
Quite common would be that you have to deal with many global variables. In OOP applications it shouldn’t be that the output of the function is influenced by global parameters. And for correct testing you need to refactor this.
Both cases need to be addressed by you - and this is where the refactoring starts. As I wrote in the last posting - while writing the test you have to refactor otherwise you can’t create proper tests.
But what to do with PHP super globals $_GET, $_POST, $_SERVER, $_COOKIE etc.? They are globals by PHP nature. You could create a wrapper (proxy) myInput::getParameter(‘getParam’) and use it everywhere in the code. No exceptions allowed. Doing so you can stub these calls also. And furthermore it adds a bit more security as you can add in this function the very basic and idiotic security checks. They won’t be enough for sure - but it’s a start.
The same applies to the global configuration parameter. The most important here is – you must be able to supply your own parameter in tests here. This way you can write tests for different request parameters and config options. On test tearDown() all parameters should be restored to defaults.
Let’s see how this could look like. You might find such settings in your code:
class someOtherClass { var $setting; function calculateSomething($a, $b) { return $a+$b; } } class myOldNastyClass { function needToTestThisFunction() { $class = new someOtherClass(); $z = $_GET['input']; // .... return $class->calculateSomething( $class->setting, $z); } }
This code has more or less all the pitfalls you will explore while dealing with globals. Before you can even think of writing a test for this you need to refactor it. And this could lead to:
class someOtherClass { private $setting; public function calculateSomething($a, $b) { return $a+$b; } public function setSetting($set) { $this->setting = $set; } public function getSetting() { return $this->setting; } } class myInput { public function getParameter($name) { return $_GET[$name]; } } class myOldNastyClass { private $input; // set e.g. in constructor public function needToTestThisFunction(someOtherClass &$class, $z) { $z = $input->getParameter('input'); // .... return $class->calculateSomething( $class->getSetting(), $z); } }
Now we have some code we can test. Let’s see how the tests could be:
class myStub extends someOtherClass { public function getSetting() { // fixture return 99; } } class myInputStub extends myInput { public function getParameter($name) { // fixture return 999; } } // in the test $test = myOldNastyClass->needToTestThisFunction( new myStub(), 88); // ....
I hope I could point you in the correct direction

