Thursday, December 19, 2013

Final day: some observations about extension building with Extension Builder and Extbase

We've arrived at the last week of the Hackership, and my goal this week was to master get pretty good at PHPUnit testing. To that end, I'm creating mock objects to test interactions in my "Organization" class with classes that have not yet been implemented. I ran into a tricky problem with this, in that the "magic" that Extbase is supposed to conjure in the following line:

/**
 * Contacts of Organization
 * 
 * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\YouthAct\Domain\Model\Person>
 *
 */
protected $contacts;

doesn't actually work. Trying to use "contacts" later in the class leads to the fatal error "Call to member-function on a non-object". Thanks to a lot of help from one of the Hackership organizers, we found out that the "initStorageObjects" function, which instantiates the related objects, isn't complete:

protected function initStorageObjects() {
$this->contacts = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}

public function __construct() {
$this->initStorageObjects();
//if you don't add this following line of code, Extbase magic suffers an epic fail:
$this->setContacts($contacts);
}

This kind of sucks. But at least now I don't get any more fatal errors: just errors about problems with my code. This is a good thing - this is how we learn! Using mock-objects allows me to test interactions of the class I'm testing with classes that haven't yet been implemented. This is a great alternative to creating a bunch of skeleton classes and wiring them up together. Additionally, using mock-objects to imitate the behavior of classes within an aggregate root makes for lean, strict and correct PHPUnit tests.

This week I built an Extension from mostly scratch, based on two domain-entities created with Extension Builder and implemented test-first with PHPUnit tests. Writing a hundred tests for getters and setters can lead to catatonia, so I decided to "see what would happen" if I were to supplement my domain-model with Extension Builder to include all domain-entities with their properties. My hope was that EB would create the new classes with getters and setters, and magically generate the test-files with the tedious setter and getter tests already done. Without breaking any of the code I'd already written. Hope springs eternal.

A note before I dive right in: no matter what your settings are in the "yaml.settings" file (i.e. "merge"), updating your domain model with the Extension Builder after having written your own code WILL OVERWRITE (almost) EVERYTHING. ALMOST everything. If it really overwrote everything, at least the code errors would be consistent! Luckily I made a hard backup of my files so that I could compare them to those generated by Extension Builder.

All of MY test code - gone. All of the setter and getter tests I had supplemented - overwritten. EB overwrites all the "getter" tests with yawning emptiness. Let me repeat: if you do not make a backup of your tests before expanding your domain-model with Extension Builder, EB WILL OVERWRITE YOUR HOPES AND DREAMS, leaving you in a yawning lacuna of existential emptiness. Hell is dynamically-generated code.

If that were not enough, here's an additional disadvantage: in its tests, EB takes care of class dependencies by instantiating objects instead of mocking them. This causes an interdependence between test classes that is NOT a good thing, and makes for test code that is difficult to correct when running it leads to failed tests. Additionally, EB has a strange habit of changing all "implements \TYPO3\whatever\this\interface" into "implements TYPO3\whatever\this\interface" EVERY time you save the domain-model through EB which, of course, leads to a fatal error which you will have to correct every time after pressing "save". Eventually I just commented out the "implements" and wrote it in after I was definitively done "saving" (ha!) the model with Extension Builder.

But wait, there's more! Everywhere a class needs to extend "Persistence\ObjectStorage", EB likes to overwrite that with "Persistence\Generic\ObjectStorage". This breaks all code, everywhere, and you will have to do a search-and-replace to get rid of the introduced errors.

"Extension Builder" might be more aptly named "Extension Wrecker". Take heed.

I ran the tests generated by EB again and again until everything passed. I think that that took as much time as writing them by hand, and the errors I had to correct were not actually introduced by me. THANKS (dripping with saracasm), Extension "Builder".

One good thing is that the otherwise nefarious Extension Builder actually added tests that helped me uncover the correct way of implementing, getting and setting storage objects. This was done in 2 different ways in the code I downloaded for "Reliable Extensions" and I'm glad that there were dynamically generated tests that could point out to me the flaw in logic in one of the implementations.

OK, so I think I'm done bitching for now. But I've come to the conclusion that, just like with the old "kickstarter" extension builder, you should really only use Extension Builder ONCE - or, never, ever again after you've started working with the code it generates. Seriously. I'm looking forward to see what the process is in my new place of employment: EB first, EB never, or EB always and forever?

It's been a very long, very productive, frusterating and also incredibly rewarding six weeks. Several times during my learning process I was able to move forward only with the help of fellow-students and organizers. At home, when I got stuck, I would always have to give up (Laravel, I'm looking at you -- YOU'RE NEXT).

It was especially in these past two weeks, where I could concentrate on domain-driven-design and test-driven-development with PHPUnit, that I've become a more professional object-oriented PHP coder than ever before. Within this short time I've gotten farther than in a whole TWO YEARS of working full-time with procedural PHP, taking online courses (in everything BUT PHP), and going to one to three programming meetups a week!

Thank you, Hackership, organizers and fellow-students, for giving me the opportunity of a lifetime - the opportunity to become a better programmer, to really learn, and practice, and share. Your support, your enthusiasm, has kept me going when things got frusterating, when it was too cold outside to want to get out of bed, when I came home after 9 hours of coding completely exhausted. You were motivation and reward.

I feel like I now know what it's like to work on a team that feels like a family.

Tuesday, December 17, 2013

Day 19: PHPUnit testing for TYPO3, the success story

Erfolgserlebnis! 

Today, with a lot of help from a hacker-in-residence, I figured out how to get my PHPUnit tests for TYPO3 running. The problem stemmed from the fact that, instead of extending PHPUnit_Framework_TestCase, TYPO3 tests extend their own Test class that serves as an autoloader for TYPO3 dependencies. PHPUnit from the command line doesn't recognize that without the help of an executable (included with the TYPO3 source code) called "cli_dispatch.phpsh".

This file can be found in the main "typo3" folder of your TYPO3 installation. To run PHPUnit tests with TYPO3 dependencies - presumably as part of extension development with Extbase - here's what you need to do:

On the command line, navigate to the directory right above where your "typo3" folder is found. On my local machine, that's:

$ cd /var/www/html

Call phpunit as the argument ("cli key") for the cli_dispatch.phpsh file, run as an exectuble. Follow the "phpunit" argument with any phpunit configurations you'd like (configuration file, colors, strict, etc.) and then the file you want to test - just as if you were calling phpunit directly from the command line:

$ ./typo3/cli_dispatch.phpsh phpunit typo3conf/ext/sjr_offers/Tests/Domain/Model/OrganizationTest.php

If you're like me, nothing will happen - you'll just get a new command line without output. To find out what the problem could be, you can call the following code on the command line:

$ ./typo3/cli_dispatch.phpsh phpunit status; echo $?

If you get "1" as output (which means, cryptically, "error"), you still need to change the following configurations in the TYPO3 Install Tool in order to get a better idea of what's going on:

$TYPO3_CONF_VARS['SYS']['displayErrors'] = 2;
$TYPO3_CONF_VARS['SYS']['devIPmask'] = '*';

This will tell TYPO3 to output errors as long as the caller's IP address matches TYPO3's IP address (i.e., if we are in a development environment). Setting the "devIPmask" to "*" tells TYPO3 that all callers' IP addresses should be accepted as "matching".

Thank you, @Christian Weiske, for this tip - you seriously saved my day!

After doing this, you should get a more detailed error of phpunit's problem. For me, it was insufficient write permissions on the typo3temp file, where locks on files are set up and log files are written. After adding some group write permissions on this file, running the "status" command got me a PHPUnit error, which means that PHPUnit is now working - awesome!

Running the code from above again,

$ ./typo3/cli_dispatch.phpsh phpunit typo3conf/ext/sjr_offers/Tests/Domain/Model/OrganizationTest.php

PHPUnit runs through all assertions in the test without problems and gives me a status report. Gods, I'm so happy I could just cry. :)

For now, I'm going to put off running PHPUnit tests from Eclipse on hold, in order to write some tests and have more of that "success experience" today, after the horrible Day of Failure that was yesterday. I'm going to create a new extension with Extension Builder, modelling the same domain model and start-functionality as the "sjr_offers" extension used by the book and import it into TYPO3. Then I will create the "Tests" directory structure in my extension and start implementing tests for each functionality. I can run them through PHPUnit and compare my efforts with the code from "Reliable Extensions". I'd also like to write a configuration file ("phpunit.xml") that loads my command-line configuration for me - without breaking anything!

Stay tuned...

After a lot of googling, I'm going to have to guess that this suggested procedure is a sensible one.

Wednesday, December 11, 2013

Day 18: PHPUnit-Eclipse hacker hell on earth

Feels just like Christmas!

I don't even want to go through the list of all the stuff I did today, trying to get my TYPO3 PHPUnit tests to run successfully from within Eclipse. I spent the last 2 hours of yesterday evening trying things out, and today it went on as I tried some new ideas I'd gotten while washing dishes this morning, and then going back to basic concepts by reading everything I could find on PHPUnit and Eclipse.

Unfortunately the majority of articles online about this topic are from 2011 or 2012.

I wrote a phpunit.xml and a bootstrap.php file for the project and, along the way, learned some interesting things about Eclipse that helped me to understand it better, like how I can set up a view for PHPUnit output in its own window and set up a button in the toolbar for running the unit tests with a click of a button instead of right-click - select - select, open console because it won't stay pinned and disappears as soon as I right-click on a file in the project-tree... (I found out that you can fix that by selecting "Restore" within the console window).

My final strategy was that on which I stumbled yesterday evening: google the error-message. "Fatal error:  Call to undefined method PHP_CodeCoverage_Filter::getInstance()". What I found is that there are two possible PERL libraries for PHPUnit to use in Eclipse, thus there are two possible "Filter" classes for PHP Code Coverage. The one being used no longer has the method being called - it has no constructor and looks like an older model.

I guess that when the code for PHPUnit in Eclipse was updated, IT WAS NOT TESTED WITH PHPUNIT. OH THE IRONY.

What I did was make a copy of each Filter class and include both of them in each library. Then in the file where the error is raised, I changed the require_once directive to require the file with the needed code.

The reason I did this is because though I entered both PERL paths as the PHPUnit libraray in Eclipse, whichever one I picked as the default, the behavior remained the same.

This fixed the problem in Eclipse, and showed me the error that I was getting from running the same unit tests from the command line. Looked like some kind of autoloader problem. After lots of trial and error, I decided to get back to basics and build the same class and test class in a simple setup without any TYPO3 extras. By doing this I figured out a few things I had done incorrectly with the bootstrap and phpunit.xml file, for instance, forgetting the "includePath" tag for where to find the classes corresponding to my test classes (doh!).

Going back to the TYPO3 PHPUnit test files in Eclipse, the autoloading problem was still the same. I finally decided, with less than two hours left until the day is over, to continue going through the tutorial from "Reliable Extensions", while building out the test classes in my simple environment. At least then I will get some practice with assertions and the basics of test-driven development. At the same time, I will continue developing them (as they should be developed) in my TYPO3 environment without even bothering to run them.

Today I spent the whole day trying to get something to work, that did not work out in the end - and I have four, dull handwritten pages recording all the steps I took and the logic I used. It made me aware of the fact that my first strategy in trying to fix a problem is trial-and-error. When my frusteration gets too great, I take a break and then get back to basics, to reset my mind and get it unknotted. Finally, if I think that it's really, really not going to work, I stop hammering myself in the head with it and do something similar that I know DOES work. In this way, I am going to get through this fu chapter, hopefully within the next one and a half hours, and be ready for the next chapter on building the persistence layer tomorrow.

I can't wait to be able to ask experts about how to solve these problems and get some insight into how they work, what their process is. If anything else, I've learned to be impatiently curious about how to solve all the difficulties I've come across and was not able to solve on my own. TYPO3 remains a challenge.

Tuesday, December 10, 2013

Day 18: Chapter - modelling the domain

Today I'm going to tackle Chapter 5 in "Reliable Extensions": Modelling the domain.

The step in which we abstract a part of the real world (the "domain") into a representation within the extension is called "domain modelling" and is, according to "Reliable Extensions", the most important part of extension development. The book uses the "sjr_offers" extension as an example of how to model a real-world domain: namely, this extension was developed for the "Stadtjugendring Stuttgart e.V." (Youth Organisation Ring Stuttgart). Whereas yesterday we developed a simple extension with the help of Extension Builder, today we're going to model the example domain by hand, using the principles of test-driven-development by writing PHPUnit tests before implementing functionality. Whee!

Looking at the list of desired functionalities, I sketched out a primary list of actions and from this list, gleaned a bunch of terms I thought might be part of the domain models. I was mostly right - yeah! Luckily, though the book (and the example domain) is in German, extensions are developed in English and I don't have to translate back and forth.

I then sketched a primitve design of how a few of the models are associated with each other - again, there was a pretty good match between what I had supposed to be the model associations and what the book revealed. This is only because the book also started with a very basic model and then refined it, step by step.

In the process, I learned a useful trick for abstracting pair-properties within a model. For example, if we have the properties "minimum age" and "maximum age", "minimum participant number" and "maximum particpant number" and "start date" and "end date", these pairs have their own rules that only apply to the two properties within the pair, and not necessarily to their aggregate root model (in this case, "activity offer"). Therefore, these pair properties are all extracted to their own models: ParticipationRange, AgeRange, and DateRange.

Furthermore, each of these new models have something in common that can be further abstracted, and that is a minimum value and a maximum value. "Reliable Extensions" extracted these generic properties into their own domain model: RangeConstraint. The models for AgeRange, ParticipantRange and DateRange are now associated with the RangeConstraint model.

This is an incredibly useful tip - this is exactly the kind of thing I want to learn from people who have more experience working on complex (real-world) projects. Thanks, @Sebastien Kurürst and @Martin Helmich!

On to implementation. My questions from yesterday, about how to take a test-driven approach to extension development, were answered neatly today. There are two ways to implement a domain-model: the "top-to-bottom" approach starts with aggregate root objects, like "offer" or "organization", that "contain" other models. The "bottom-to-top" approach does the opposite and starts with the elementary objects contained with the aggregate root. The approach you decide to use will have an effect on how tests are written - "Reliable Extensions" paves the way with the top-to-bottom approach, tackling the big ol' "organization" model first.

Yesterday, basic domain models were implemented as PHP classes for us by the Extension Builder and saved in the "Classes/Domain/Model" directory. Today, we create these classes by hand. Instead of, however, starting with "Organization.php", we will start with "OrganizationTest.php", which we will create in the Tests/Domain/Model" directory.

I decided to bite the bullet and start actually using Eclipse to develop. Following the instructions from last week, I started a new project, "SrjOffers" and linked the PHP paths "Extbase", "Fluid" and "PHPUnit" to my new project in order to set the basis for auto-completion. In order to do this, you need to make sure that the owners and permissions for the root directories of these libraries are correct.

"Reliable Extensions" recommends that the structure of the "Tests" directory should mirror that of the "Classes" directory, in order to keep everything clearly arranged as the number of unit-tests grows. I'm wondering, though, if I should start with "Tests/Unit/Domain/Model" instead of their recommended structure "Tests/Domain/Model", to make room for other kinds of tests later, like integration and acceptence testing.

So, the first unit test is written... how do I run it in Eclipse? I know how to run unit tests from the command line and from within the TYPO3 backend. However, since we're writing this extension by hand, it is not yet an official "extension" in TYPO3 and therefore cannot be connected with unit tests. Hello again, my friend Google. "PHPhatesme.com" was an excellent source of information for this question:

Under "Help" -> "Install new software", click on the "Add" button and enter "http://www.phpsrc.org/eclipse/pti-dev/" as URL and "PHP Tool Integration" as the name. Now, select this site from the dropdown and open up the lists that appear in the select box: Core, Library, and Tools. Select the PTI core under "Core", PEAR under "Library" and "PHPUnit" under "Tools". You know what's really cool? Under "Tools" you can also pick PHP Code Sniffer, PHP Copy-and-Paste detector, PHP Mess Detector, and PHP Depend, if you want to.

Eclipse will install your selections and then you have to restart. Now, when I right-click on my OrganizationTest.php file in the project tree, I can select from the menu "PHP Tools" -> "PHP Unit" -> "Run Unit Test". Unfortunately, what this produces in the console is "No case / test suite found for file OrganizationTest.php". I'm guessing that I have to write a bootstrap file? I wrote to the forum on the article on "phphatesme" - because, PHP does hate me, apparently.

Despite all of our difficulties, PHP, we've been through so much together, and after 15 years of ups and downs I'm obviously still willing to work on our relationship, 'till death do us part!

I have two specific problems now: 1) why isn't Eclipse auto-completing the code I write in the class inheriting from \TYPO3\CMS\Extbase\Tests\Unit? and 2) why can't PHPUnit find my class to test? Both seem to be related, because the error message I get when running PHPUnit on the command line is that "Class TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase not found".

Problem 1: with the help of two co-hackers we saw, first of all, that I had typos in my name-space and directory-name (eye-roll). Fixed these, deleted the project, re-imported the correctly-named project in Eclipse, and tried again. Same error. With some more help and prodigious googling, we came up with the following solution by @Carsten König:

Bind TYPO3 as a library in Eclipse - for autocompletion on all Typo3 libraries


  1. Open "Window"->"Preferences".
  2. Select "PHP"->"PHP Libraries" -> "New...".
  3. A window titled "User Library" will pop up prompting you to enter a name. Type the name "TYPO3" and click "OK".
  4. Select the new entry, "TYPO3" and then "Add external folder".
  5. Browse for the "typo3_src" file - on my system, it was in "\var\www\buch\html\typo3_src", select it, and click "OK".
  6. Right-click on project that should have auto-completion. Select "Properties" -> "PHP Include Path" and click on the "Libraries" tab.
  7. Choose "Add Library" and check the box next to "TYPO3". Click "Finish" and then "OK".

This worked in that writing a test class that extends the TYPO3 BaseTestCase, which in turn extends the TYPO3 Core UnitTestCase, calling "$this" gives me a long list of methods from PHPUnit to choose from. I still get the same error running the unit test in Eclipse, though (and a probably related one on the command line).

Running PHPUnit on one of the files "without detection" gives me the error "PHP Fatal error:  Call to undefined method PHP_CodeCoverage_Filter::getInstance() in /home/kaiser/programming/zend-eclipse-php/plugins/org.phpsrc.eclipse.pti.tools.phpunit_0.7.2.R201106270000000/php/tools/phpunit.php on line 40".

I report this after 2 hours of searching for an answer. The command line error remains "can not find (TYPO3 BaseTestCase) class". Enough for now, though; I've been working for nearly 9 hours and it's time to take a break.

To be continued, friends (and enemies) of Typo3...

Monday, December 9, 2013

Day 17: building another simple extension with Extension-Builder.

Today I tackle Chapter 4 of "Reliable Extensions", which involves building a(nother) basic extension with Extension Builder. To review, building an extension involves the following steps:

1. Create a directory structure and the basic configuration files.
2. Model the problem domain.
3. Configure the persistence layer:
   a) define the database tables.
   b) configure the backend forms.
   c) set up the repositories.
4. Define the inner processes of the extension (design the controllers and their action methods).
5. Design and implement HTML templates to present data.
6. Create plugins ("plugins" in Typo3 always refer to the frontend) for listing data.
7. Install and test extension.

Wait a minute... why does testing the extension come last in the steps? If I want to use test-driven-development in creating an extension, what's the best approach? Do I test everything, or only the controllers and their action methods? I'm guessing that testing these, at least, would be a good start, but should I generate test-cases after the code for the extension is generated by Extension Builder, or beforehand?

Extension Builder (from now on referred to as "EB" to spare me some typing) takes care of all the above-listed steps except for 7: basic configuration (step 1), plugin - frontend - configuration (step 6), and domain-modelling (step 2) are done through EB's graphical interface. On saving, EB generates the directory structure (step 1) with the following folders: Classes/Controller, Classes/Domain/Model, Classes/Domain/Repository, Configuration/TCA, Resources/Private/Templates/Product, Tests/Unit, and some others.

Under "Configuration/TCA/", the PHP class, "Product", is configured to allow us to determine how the forms in the backend should be shown (step 3b). Additionally, in "Classes/Domain/Repository/ProductRepository.php", EB has generated a class for us that will allow us to access the data of our persisted models (step 3c).

In "Classes/Controller/ProductController.php", EB has generated a controller and its action methods for us (step 4) as we have determined them in the "default actions" section of the EB graphical interface. Here, the action methods access our model data through a repository, and then assign this data to a view for presentation. A basic first template for the view for the "list" action has been created for us (step 5 - thanks, EB) under "Resources/Private/Templates/Product/list.html".

Basic configuration files are saved in the main directory named after our extension key - in this case, "inventory" - and are all preceded with the prefix "ext_". For instance, the file "inventory/ext_tables.sql" provides the SQL commands necessary to set up the database tables accomodating our domain model (step 3a), "inventory/ext_localconf.php" defines for our frontend plugin which controller-actions are allowed, and "inventory/ext_tables.php" registers the plugin for the frontend.

The entire generated directory structure is stored in the main directory for our local extension: "inventory". This, in turn, is stored where all local extensions are stored, in typo3conf/ext. In contrast, global extensions, which are globally available to every page, are stored in typo3/ext, and system extensions, which are valid for the entire TYPO3 installation, are saved in typo3/sysext.

Finally, we reach a point where we actually have to do something ourselves: install the extension. Under "Extension Manager" / "Manage Extensions", you'll find the "Inventory" extension - click on the icon to activate. Logout, and login again - if you're lucky, nothing's broken.

Set up a system folder in your page tree. I'm calling mine "Inventory" (duh). Once it's created, add a new record to this folder of the type "Product" - in the list of plugins, you should see this under the plugin "Inventory". You can repeat this last step to insert as many products as you like into our new inventory database.

Now you can set up pages that use the plugin. Just add a page of type standard in the page tree, go into the list view on this new page, and add a new content record of type "Insert Plugin". Choose "Product List" as the "type" under the tab "Plugin". Also set the "Record Storage Page" (under the tab "Behavior") to the system folder "Inventory", and you should see our list of inventory records in the frontend.

Unless you're using TemplaVoila: then you'll just see the ID of the page's content-record. I'll have to figure this out tomorrow.

Today I've accomplished my goal of working through chapter 4 of "Reliable Extensions". I also read a chapter from "Advanced PHP" on saving session variables to the database instead of the file-system, during my lunch "break". Tonight I'll see if I have the energy and the desire to finish Code School's "Git Real" course after dinner. Or if I decide to just crash on the couch and engage in staring contests with my cats. What I do know is that I am the most unhip programmer in Berlin for admitting that last bit.

Thursday, December 5, 2013

Day 16: OOP, DDD, TDD, and MVC in Typo3. And something about me.

Day 16

Today I once again got through one chapter of "Reliable Extensions" with a lot more success than yesterday. For example, today's chapter, on object-oriented programming, domain-driven design, test-driven design and the Model-View-Control pattern, where I often referenced my "Hands-On with PHPUnit" book for additional information, was 40 pages. Yesterday's chapter was 8.

First off, I started the day with a revelation: I learn better when the rest of my life is in order. When the apartment looks decent and I have clean clothes to wear, healthy, home-made food to eat, groceries in the cupboard, a legally valid public-transportation ticket, and all errands run. Because then my head is clear for other things, like refreshing my knowledge of concepts important to OOP (object-oriented programming).

Objected-oriented-programming is a programming paradigm that assumes that processes in the world can be abstracted into and represented by models (or objects), and the relationships and interactions between those objects. Objects have relationships, just like in the real world: a car HAS a motor. A Volvo IS a car. A Smart WANTS TO BE a car... These relationships can be one-to-one (a car has ONE steering wheel), one-to-many (a car has FOUR - or more - wheels) or many-to-many: a City-Car is driven by MANY drivers, Michael Jordan drives MANY cars.

The objects closely or inseperably involved in a "has a" or "belongs to" relationship can be described as aggregates: for example, wheels, brakes and a motor belong together in a car. The car would constitute the "aggregate root object" since it represents its composite parts as belonging to a complete whole. An aggregate root object, just like a car, must be an individual object in the world. We call an object that can be an individual object in the real world an "entity". In contrast to an entity, a value ("value object") would be something like the color blue, or the number 1. Blue is blue - it wouldn't make sense to say that it was an individual in the world.

Another concept from the world of OOP is the idea of "services". Services are containers for actions that can't really be attributed to any object. A service should be "stateless", that is, it should have no internal status that can be changed or manipulated. A service is kind of like a verb, where objects are more like nouns: a car can have a state (in motion, at rest) whereas "to drive" can't really be talked about that way. A service usually receives an entity or a value object whose state it can manipulate or change.

In the world of software, which consists not of REAL objects, but of mere representations of objects, the act of keeping these objects around in the virtual world (in memory or on the hard drive) is known as "persisting". In the world of OOP, the act of persisting an object is the responsibility of "repositiories". A database could be called a repository. It's responsible for "remembering" an instantiated object and its state so that it can be used in a program with consistency.

Our object-representations (let's just call them objects so that I don't have to type so much) can be created with factories. A factory is something that builds complex objects and sets all their properties before giving out the complete object at the end for use. In OOP, we use either a factory or the "constructor" method of a class to create an aggregate root object and set all its properties with consistency.

Aggregate root objects and persistence are tied together in that every aggregate root has to have exactly one repository: something (even a virtual something) can only be in one place at one time. In Extbase (ay, there's the mark of the matter), we define an aggregate root by creating its repository first.

On to MVC: Model-View-Control. The MVC is a pattern that can be used when writing software that (when used sensibly) will make software easier to read, maintain, and develop further. This is because the MVC pattern seperates software functionalities into distinct areas of responsibility: the Model, the View and the Controller.

The model is responsible for encapsualting data, the logic of how the data is used, how it's accessed, and how it's persisted. The view is responsible for presenting data to the user. Finally, the controller is responsible for coordinating the interaction between the model and the view. It ONLY coordinates: the actual domain functionality is implemented in the model. In Extbase, the model is further structured into domain model (abstraction of the domain, its logic and rules), repository (database access), and validator (container for the "invariants of the model", whatever that means) .

This brings us to DDD: domain-driven-development. What's a doman, you ask? It's an area of special knowledge and specific processes that belong together. For example, a hospital (the domain) has admissions, appointments, examinations, surgeries, therapy, medications, medical records, etc. The goal of a software developer who wants to develop a program to make these processes easier (cheaper, faster, more reliable, less tedious, compliant with the law) for the people who work within the domain, is to understand the language of this area and these processes. In order to do this, she has to sit together with someone who knows the domain inside out (and does actual, competent WORK within it...) and together with them, develop a way of talking about this domain that both developer and domain expert can understand.

This way of talking about the domain that both developer and expert (and software user) can understand is called "ubiquitous language" and can be best made useful by developing a kind of dictionary, or glossary, of terms, that both developer and domain expert can refer to. This glossary can then be used by the developer to implement software that is easy to talk about with the expert/user and to check with them that the desired functionality has been correctly understood and implemented.

Here's a personal aside: I use the hospital example because it's the domain in which I have had over 10 years of experience developing software for. By this point, I'd consider myself both a developer of software as well as a domain expert for hospital administration processes. I got there by consistently asking to watch how my colleagues work, asking them to tell me all about the way they do things, and then asking them questions about things I didn't understand or weren't clear. I would then sketch out a step-by-step example of a program and go through it with them, asking them at each step if what we were talking about made sense and corresponded to the way they needed to get their job done. I would do this again and again until they were satisfied with what we had worked on together, and only then would I start programming.

Only when I did NOT do this (for example, when the domain expert believed that they could communicate with me indirectly about what they "needed" by telling my boss about it, or in an incomprehensible email, or via telepathy), or the domain "expert" did not actually do any real WORK in the area they were supposed to represent, that software "got developed" that was of no use to anyone. Domain-driven-design makes sense to me - it's the only way to possibly make something that someone's going to be happy with and actually use.

So I already have a good handle on - and years of experience with - domain-driven-design. What I lack an intuition for is TDD - test-driven-development. I'm familiar with the theory, which I refreshed today, and have started to implement it in baby-steps: trying to code the example and then checking out the code provided by the book to see how close it is, if I have the idea right, what's missing, what's totally wrong, what I've failed to understand or succeeded in getting right.

That made today a fun day. Just in time for the weekend.

Wednesday, December 4, 2013

Day 15: way too many problems

First of all: @Dmitry Dulepov saves the (first part of the) day. Thank you, Mr. Dulepov.

"There is a question that I see several times monthly in TYPO3 mailing lists: "I see an empty (blank) page after XXX. How do I fix it?". Here is the step by step answer:

Go to the Install tool
Select "All configuration"
Set displayErrors to 2
Add your IP address to devIPmask
Now you will see PHP errors that happen. By default these errors are hidden by TYPO3 for security reasons and it causes blank pages. Changing settings above allows to see these errors on your IP address only.

So fix these PHP errors and your site will be back."

Source: http://www.dmitry-dulepov.com/2009/03/blank-empty-page-in-typo3.html

I had this problem, namely, after installing Xdebug as instructed in the "Reliable Extensions" book project.

In the Install Tool, "Configuration All", the "displayErrors" parameter has a value of "1", which means:

"Default setting. With this option, you can override the PHP setting 'display_errors'. If devIPmask matches the users IP address the configured 'debugExceptionHandler' is used for exceptions, if not 'productionExceptionHandler' will be used."

We need to change it to "2", which means:

"Display errors only if client matches [SYS][devIPmask]. If devIPmask matches the users IP address the configured 'debugExceptionHandler' is used for exceptions, if not 'productionExceptionHandler' will be used".

Re-opening the "Extension Manager" / "Get Extensions" page, I feel so enlightened; here's my error:

"( ! ) Fatal error: Maximum function nesting level of '100' reached, aborting! in /var/www/buch/typo3_src-6.1.5/typo3/sysext/core/Classes/Utility/GeneralUtility.php on line 1125"

I fixed this - after some googling and detouring - by entering the following line of code in my php.ini file:

xdebug.max_nesting_level = 250

I had a hard time figuring this out because I assumed that this line would already be IN the php.ini, because that's what my phpinfo() was telling me. Apparently the default is used, without an explicit line of code in php.ini, so if you want to change it, you have to write it out yourself.

Next, I was forced to undergo an HOURS-LONG detour in that I returned my edition 1 of "Reliable Typo3 Extensions" and bought the 2nd edition from O'Reilly books. I love the English version of the O'Reilly books site, but unfortunately the German site - which has NO user registration - sucks, and I got the Ebook as link in an email to a PDF... which I was not able to bring over to join my Ebooks on the iPad.

Sigh.

So I settled for working with the book as a PDF on my laptop. But installing the "blog_example" (new, version 1.4) extension provided by the authors or "Reliable Extensions" (wow - the irony...) via download ended up killing my Typo3. I found out that this is because uploading the .zip file of extension as instructed writes the ".zip" part of the file AS PART OF THE EXTENSION KEY, which breaks EVERYTHING. After a LOT of cursing under my breath and combing through lines of code, I was able to get everything running again by:

1) renaming the directory under typo3conf/ext from "blog_example.zip" to "blog_example"
2) getting rid of all references to "blog_example.zip" in typo3conf/LocalConfiguration.php
3) forcibly clearing the cache by deleting the typo3temp directory

I only did all of this after first commenting out some lines of code in the UtilityManager.php so that I could get back into the backend and de-install the (shitty) extension and try to reinstall it from the unzipped version of the directory (which, of course, did not work).

Hi, writers of "Reliable Typos3 extensions": you might want to fix your "blog_example" code AND the typo on page 19 that reads "Um das Modul nutzen zu können, müssen Sie zunächst im TypoScript-Setup Ihrer root-Seite das statische Template BloxExample setup inkludieren". ("In order to use the module, you need to include 'BloxExample' (styles) in the static template of your root page." Because that's BlogExample. At least this crucial instruction is INCLUDED in the 2nd edition of the book: in the first, it was not, basically rendering the appropriate extension of "blog_example" (version 1.3) completely unusable.

Anyway... working with Eclipse and "projects" isn't really working for me today either. Why is it taking minutes to run the debugger on one line of code? Finally I got it working, but I'm irritable and annoyed so the fun of it will be hard to recover. Too many problems with software not written by oneself makes up 90% of the sucky part of programming, I think.