Deeply entrenched in government contracting as I was when I discovered agile, I have had my fair share of CMMI as well. Like the PMI, CMMI has a deep heritage in waterfall processes, yet has acknowledge the value and tried to incorporate agile and lean principles and practices into its toolbox. And lets faces it, CMMI level 5, for any company that ever makes it that far, is all about institutionalizing continuous process improvement across the enterprise. Think company-wide Kaizen, explained using waterfall terminology.
My experience is that there are opportunities for synergies between CMMI and agile, and I expect, between the PMBOK and agile as well. More germane to my interest though, my tagline on LinkedIn states “Have you ever asks, ‘How can I get the accounting department fired up about agile?’ I have.” and I have. And what I have learned is that, out side of the technology department, most companies think and speak in PMBOK terms.
So my three-fold reason for taking the PMP is this. First, I really believe there is useful information in there that is going to help me run my lean projects better. Second, I want to be conversant in the terminology of those I am looking to win over, and third, having PMP after my name will help me get my foot in the door with certain people to have those conversations.
That is not what this article is about however. That is just the context. What I want to throw out there is this idea that is percolating in my head as I sit in these classes and think, how do I get the accounting department fired up about agile?
My biggest objection to the class is just how impractical it is. It is (understandably) teaching to a test. Its an attempt to cram into the heads of up-and-coming project managers a high level understanding of everything they might ever need to know about project management. So here I am, working with people some of whom have never run a project that ran longer than a few months, never had a formal charter nor budget, etc. And they are trying to get their heads around scheduling, budgeting, command and control and every other knowledge area that you might need if you were building the next big thing in Abu Dhabi.
There is this disconnect. To pass the PMP exam, what we are getting is a cram course, a survey if you will, of the depths and riches of the PMBOK. But the expectation is, or seems to be, that if you pass the PMP, you actually know something at the practical level about how to run a project along PMBOK lines. My experience to date is that this will not be the case, nor does the remainder of the syllabus suggest differently.
I have a plan to address this. Lets get our PMP, but lets not stop there. We need a mentoring program for newly minted PMs that starts with the one or two PMBOK processes most applicable to the project at hand and helps the mentee to tailor those processes for and learn to use them on their project. Once they have begun to show mastery at using and tailoring those processes, and as they move on to bigger more complex projects, the mentoring process will assist them in identifying, tailoring and integrating other processes.
And, lest you forget that I am an agilist–the company’s legion of scrum masters, lean nijas and the like should be deeply integrated into this mentoring program. The goals that the PMBOK processes have are both good and eminently attainable using agile practices. Our implementation of them should be strongly informed by lean and agile principles–our companies “organizational process assets.” In this way we can, across the whole company, PMPs and SCMs alike, tech and accounting, HR and marketing, all develop a common language and understanding of delivering the right thing, on time and on budget to high ROI. That is what it is all about in the end is it not?
And who knows? Maybe by the time I retire, the accounting department will finally accept my iterative annual budget, delivered just in time to spend. Now that I know to present it as “progressively elaborated!”
Using $http to post a blog entry for example is pretty easy:
myPost = id: 123 title: 'Using HTTP Interceptors to Deserialize Dates' status: 'draft' creationDate: new Date() body: 'TBD' $http.post('/api/blog', myPost) |
This results in the following JSON being posted to the server:
{
"id": 123
"title": "Using HTTP Interceptors to Deserialize Dates",
"status": "draft",
"creationDate": "2014-08-13T10:13:39.399Z",
"body": "TBD"
} |
This is great. Notice that the service has automatically serialized the creation date to an ISO-8601 compliant string. I couldn’t ask for more… or could I?
What if I want to now get that post back:
$http.get("/api/blog/123").success (blog) -> console.log blog.creationDate console.log typeof blog.creationDate |
Assuming that the endpoint returns the exact same JSON that was just posted, this code will output:
2014-08-13T10:13:39.399Z string |
This is not the end of the world but it may not be what one is expecting. The expectation is usually that if I put a Date instance into a serialization function, then I get a Date instance out of the matching deserialization function.
Fortunately, this situation is easily remedied with a Angular http interceptor. Angular’s $httpProvider service allows one to configure interceptors that can pre-process all out-going requests before they are sent and post-process all received responses before handing them back to the calling application. A response post-processor to find all ISO-8601 date strings and convert them to actual Date objects is easy to implement.
angular.module('myModule', []).config([ '$httpProvider' ($httpProvider) -> $httpProvider.interceptors.push [ -> #Matches YYYY-MM-ddThh:mm:ss.sssZ where .sss is optional iso8601RegEx = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/ response: (response) -> convertDates = (obj) -> for key, value of obj #If it is a string of the expected form convert to date type = typeof value if type is 'string' and iso8601RegEx.test value obj[key] = new Date(value) #Recursively evaluate nested objects else if type is 'object' convertDates value convertDates response.data response ] ]) |
And there you have it. Happy coding!
]]>@@ -1517,10 +1517,11 @@ var requirejs, require, define; * A load event could be a script load or just a load pass from a synchronous * load call. * @param {String} moduleName the name of the module to potentially complete. */ completeLoad: function (moduleName) { + console.log('Completed load of ' + moduleName); var found, args, mod, shim = getOwn(config.shim, moduleName) || {}, shExports = shim.exports; takeGlobalQueue(); @@ -1635,10 +1635,11 @@ var requirejs, require, define; }, //Delegates to req.load. Broken out as a separate function to //allow overriding in the optimizer. load: function (id, url) { + console.log('Loading ' + id + ' from ' + url); req.load(context, id, url); }, /** * Executes a module callback function. Broken out as a separate function @@ -1646,10 +1647,11 @@ var requirejs, require, define; * layer in the right sequence. * * @private */ execCb: function (name, callback, args, exports) { + console.log('Initializing ' + name); return callback.apply(exports, args); }, /** * callback for script loads, used to check status of loading. |
F.Y.I. This diff was applied to Require.JS 2.1.10
]]>Recently, I have been doing some in-browser automated testing with Testem and Mocha. For continuous integration purposes we are using the PhantomJS headless browser.
All was fine until one day when—boom—a bunch of new tests, which I had written and debugged in Chrome and FireFox, were failing in CI under Phantom. It turns out that Phantom 1.9 has some date parsing issues and cannot parse dates of the form “2011 Feb 09 12:39:09.”
We had previously used a ISO-8601 polyfill to fix a similar problem with legacy Firefox browsers. This problem was a little different. Our date format, though understood by most browsers, isn’t ISO-8601 compliant. More importantly, the polyfill only fixed the “static” Date.parse method. In the current case, the date was being parsed by the Date constructor.
The ISO-8601 polyfill explicitly avoided dealing with the constructor and for good reason. Though I did not know it at the time, JavaScript never intended for anyone to subclass its internal Date type. (More on this later.) Changing our code over to use Date.parse and modifying the polyfill would mean touching a lot of code, and making it more complex, just for CI—something I didn’t want to do. So I set out to write my own polyfill that would handle the constructor as well as Date.parse.
My initial simple-minded approach was to just subclass Date and override its constructor, like so:
(function () { function fixStringDate (sDate) { //Implementation omitted for brevity return sDate; } Date = (function (JSDate) { function ctor() { this.constructor = newDate; } ctor.prototype = JSDate.prototype; newDate.prototype = new ctor(); function newDate() { if (arguments.length === 1 && typeof arguments[0] === "string") { JSDate.prototype.constructor.call(null, fixStringDate(arguments[0])); } else { JSDate.prototype.constructor.apply(null, arguments); } } newDate.parse = function (sDate) { return JSDate.parse(fixStringDate(sDate)); } return newDate; })(Date) })(); |
As you can see, this is pretty much boilerplate code for creating a subclass in JavaScript. And it seemed to work. After running the code, calls like new Date(‘2011 Feb 09 12:39:09’) no longer threw errors in PhantomJS. That’s the good part.
The bad part is that calling any instance method of the object so created results in a TypeError with a message to the effect of “not a date object”. This stackoverflow question outlines the issue very well. In short, Date isn’t really so much a class as a collection of static methods that only allow themselves to be called with an object whose immediate type is Date. Mere sub-types of Date don’t pass muster.
So the obvious thing to do was to create a real date object internal to the new class and delegate all method calls down to it. Thus:
function newDate() { if (arguments.length === 1 && typeof arguments[0] === "string") { JSDate.prototype.constructor.call(null, fixStringDate(arguments[0])); this.__realDateObject = new JSDate(fixStringDate(arguments[0])) } else { JSDate.prototype.constructor.apply(null, arguments); this.__realDateObject = JSDate.apply(null, arguments); } } var functions = ["getDate", "getDay", ... "valueOf"] for (var i = 0; i < functions.length; i++) { (function (funcName) { newDate.prototype[funcName] = function () { return JSDate.prototype[funcName].apply(this.__realDateObject, arguments); }; })(functions[i]); } |
This solved the problem for our specific cases and I could have stopped here. We fortunately never invoked the constructor with more than one argument.
Since we might do otherwise in the future, I wrote some tests to cover all the cases. In doing so, I found out that calling apply on JSDate (a reference to the original Date class) does not work. It runs, but the object returned is “not a Date object.”
I messed around with a lot of ways to invoke apply on the JSDate constructor including several worthy of mention. None worked in this case. Ultimately I had to resort to brute force, relying on the fact that the Date constructor accepts a reasonably finite number of arguments:
function newDate() { if (arguments.length === 1 && typeof arguments[0] === "string") { JSDate.prototype.constructor.call(null, fixStringDate(arguments[0])); this.__realDateObject = new JSDate(fixStringDate(arguments[0])) } else { JSDate.prototype.constructor.apply(null, arguments); if (arguments.length == 1) this.__realDateObject = new JSDate(arguments[0]); else if (arguments.length == 2) this.__realDateObject = new JSDate(arguments[0], arguments[1]); //etc... } } |
At this point it became obvious that newDate isn’t really acting as a subclass at all. It is acting more like a decorator around the Date type. So all the subclassing code can be removed, which gets us to:
(function () { function fixStringDate (sDate) { //Implementation omitted for brevity return sDate; } Date = (function (JSDate) { function newDate() { if (arguments.length === 1 && typeof arguments[0] === "string") { this.__realDateObject = new JSDate(fixStringDate(arguments[0])) } else { if (arguments.length == 1) this.__realDateObject = new JSDate(arguments[0]); else if (arguments.length == 2) this.__realDateObject = new JSDate(arguments[0], arguments[1]); //etc... } } var functions = ["getDate", "getDay", ... "valueOf"] for (var i = 0; i < functions.length; i++) { (function (funcName) { newDate.prototype[funcName] = function () { return JSDate.prototype[funcName].apply(this.__realDateObject, arguments); }; })(functions[i]); } newDate.parse = function (sDate) { return JSDate.parse(fixStringDate(sDate)); } return newDate; })(Date) })(); |
Having done this, I realized I was making everything much harder than it needed to be. If I am not actually subclassing Date and just decorating it, all I really need to do is decorate the constructor and return a real Date object from it. Doing so lets me drop all that messy delegation code for the instance methods. Finally my code becomes simple and clean:
(function () { function fixStringDate (sDate) { //Implementation omitted for brevity return sDate; } Date = (function (JSDate) { function newDate() { var theDate; if (arguments.length === 1 && typeof arguments[0] === "string") { theDate = new JSDate(fixStringDate(arguments[0])) } else { if (arguments.length == 1) theDate = new JSDate(arguments[0]); else if (arguments.length == 2) theDate = new JSDate(arguments[0], arguments[1]); //etc... } return theDate; } newDate.parse = function (sDate) { return JSDate.parse(fixStringDate(sDate)); } return newDate; })(Date) })(); |
Intuition tells me this code has some drawbacks that could merit a return to the subclassing solution for certain edge cases. So I am glad to have gone through the whole learning experience. Yet for now, the simpler solution is enough. YAGNI
Full code with tests is available on GitHub.
]]>I am a strong proponent of automated testing and test driven development. But if asked if I do unit testing verses integration or some higher level of testing, I will usually ask the questioner to define “unit.”
To some, this may seem like questioning the definition of “is” but I don’t think so. Consider a set of unit tests that test a single class, the stereotypical case. Let us assume the class was somewhat complex and there were fifty tests to exercise all of the code in the class. Later the class gets refactored into a facade class, supporting the interface of the original class, and a small set of simpler classes behind it that work together to do the work of the original class.
Should we now write unit tests for each of these new classes? Why? What is the ROI? If the original set sufficiently tested the original class, and the refactoring was just that, a change in code structure that did not modify its behavior, do they not now sufficiently test the classes as a group?
Indeed, in my experience, even if we started out with a set of classes that work together to perform a business function†, the best value in testing is still to write tests that test that the business function is performed correctly. Such tests will always be valid as long as the business function, i.e. the functional specification of the code, does not change. Tests below this level, in my experience, are fragile and break upon refactoring because they are too closely tied to the implementation of the code under test. If the value of testing is to enable refactoring with confidence, then the tests must survive the refactoring.
How does this fit in with TDD? In TDD we should never write code unless we have a failing test. If each test expresses a detail of the functional requirements of the software (as opposed to a detail of its implementation), then as each test passes, a functional requirement is met, we refactor and move on. It should not matter if we wrote one line, one class or a dozen classes to make the test pass.
Some may argue that writing comprehensive tests at this higher level of abstraction is too difficult. Rather one should write general tests that level. One might, for example, assert that a value is returned. But lower level tests should be written to assert that the correct value is returned for every edge case.
This can sometimes be true. Sometimes tests for edge cases at higher levels of abstraction are harder to set up than the effort is worth, and a lower level test, even if fragile, gives better ROI. However in my experience, in the general case, what makes testing the edge cases difficult at the higher level is usually the same thing that makes any testing difficult: bad design, inexperience with testing, bad tooling, or a combination thereof. Even granting that higher level tests are objectively harder to write, if one practices writing harder tests, it eventually gets easy and one becomes a better tester than they otherwise would have been.
In the end, for each business function, there needs to be an API the implementation of which is responsible for performing that function, and that implementation needs to be testable within one or more contexts (a given system state that can be mocked or otherwise simulated). If the implementation is a single function, a class or an entire module is not the relevant concern. The concern is what are the inputs and what are the outputs and testing that the anticipated inputs all lead to their correct outputs.
Yes, we want to write our tests at the lowest level possible within this context. But we do not want to go below this level. We do not want to be testing components that are simply implementation details of the software’s functionality. Such tests break under refactoring, lead to higher maintenance costs, rarely add value and hence have poor ROI.
There is an exception. For teams or developers new to TDD and writing well designed code in general, lower level tests can provide value. Writing lower level tests is easier. More importantly, being forced to make the lower level components testable helps one to learn good design. It enforces loose coupling, proper abstractions and the like. However once these skills are internalized, they can be exercised without needing to write tests to enforce them. These tests are a learning tool that can and should be discarded.
There is a corollary to this. If a developer doesn’t stop writing these low level tests once he no longer needs them, if he doesn’t instead start writing test at the business functional level, it is entirely possible to develop a system that is fully “tested” but fails to do the right thing. Every low level unit can work as intended but in aggregate fail to work together as intended. One needs tests that assert that the system as a whole, or meaningful segments of it, perform as intended.
I will conclude by admitting that I have not truly answered the question I started out with. How do we correctly define a unit? I have asserted that the best definition of a unit “the code that implements the lowest level business function.” In short we need to be able to discern the boundary between business function and implementation detail. Pointers on how to do this shall perhaps be the topic of another post. For now I will only say that finding the level of test abstraction that will maximize ROI is as much an art, learned from experience, as it is anything else. But one will never develop the art, unless one first realizes it is to be sought after. And challenging those who have not already done so to start looking is the real point of this post.
†Throughout this discussion, I am using the term “business functionality” loosely to refer to what the software is supposed to do conceptually, the details of its functional specification as distinct from details of the implementation of that specification. The term “business” itself may not be properly applicable to all real world cases.
]]>I have been working with our UI team recently to help them do better testing of their Backbone.js based single-page web application. We found it useful to bring in Squire.js to assist us in doing dependency injection into our many Require.js modules. Squire works quite well for this but invariably when writing these sorts of apps, you need to pull in libraries that are not AMD compliant at all or are simply “AMD aware.” When these sorts of modules enter the mix, Squire needs a little help.
jQuery is a great example of this sort of library. Recent versions are AMD aware, and include a define() call. Unlike a true AMD module, though, jQuery’s functionality is not fully encapsulated within the factory function provided to define. Indeed, none of jQuery’s initialization is handled in its factory function. Rather jQuery initializes upon load, just like any legacy JavaScript module. jQuery must do this in order to remain compatible with the millions of lines of non-AMD code that use it.
This presents a problem when using Squire. In order to supply alternate versions of AMD modules to the module under test, Squire creates a new Require.JS context in which to load the module under test and its dependencies. Each new Require.JS context in turn loads afresh all the javascript files that are needed by that context. If all of these files are AMD modules, whose state is fully encapsulated within their factory functions, and only initialize when told to do so, then everything is fine. In the case of jQuery, or other non-AMD modules, which initialize upon load and store state in the global space, this can be a problem.
Consider this simple example. Two separate tests use Squire to load jQuery and the jQuery.BlockUI plug-in. Depending on timing details between your browser and your web server, both jQuery instances may load first, followed by both plugin instances, or they may load interleaved: jQuery, plugin, jQuery, plugin. The latter will work out well, the former (and in our experience most typical case) will not. In the former case, because of the shared global namespace, the second jQuery module loaded is the one that the global jQuery and $ variables point to when both of the BlockUI plug-ins load. Because of this, they both plug into the second jQuery instance leaving the first one plug-in free. For non-AMD modules who access jQuery from the global $ variable, this is not a problem. The instance they get has the plugin. For AMD modules that are handed a jQuery instance as an argument to their factory function, the context that loaded the first jQuery instance is stuck with that instance, which did not get its plug-in. This should lead to a lot of failing tests.
At first pass, it may seem that the solution is to some how ensure the load order or otherwise ensure that both jQuery instances get their plug-in. That may be a theoretical ideal, but most non-AMD libraries were never designed to have multiple instances loaded and running and doing so can cause all kinds of problems. jQuery, because it supports loading multiple versions of itself at the same time actually handles this better than most. Nonetheless the best solution is to simply avoid loading multiple instances of non-AMD libraries. The question is how to do this in Squire.
Best we can tell, Squire does not explicitly support this. However, there is a simple workaround that can be put in place to enable it. The trick is to require jQuery, any plug-ins, and any other non-AMD modules that may be loading twice at the same time as you require Squire itself. Then for each of these libraries, tell Squire to mock the module and provide Squire with the initial instance as the mock. For modules that don’t return anything when invoked by Require (BlockUI plug-in in our case), Squire must still be told to mock it, but null can be provided as the value for the mock.
Here is some example code taken from a complete working example on github.
define([ 'vendor/squire/Squire', 'data/mock-data', 'vendor/jquery', 'vendor/jquery.blockui'], function(Squire, mock_data, $) { var injector = new Squire(); injector.mock('data/real-data', mock_data); //Our fix to avoid loading jQuery and BlockUI twice injector.mock('jquery', function() { return $; }); injector.mock('vendor/jquery.blockui', null); injector.require(['app/example-view'], function(View) { describe('Testing with Squire only', function() { var view = null; before(function() { view = new View(); }); it('$.blockUI should be defined', function() { assert.isDefined(view.getBlockUI(), '$.blockUI was undefined in example-view'); }); it('the data should be mocked', function() { view.getDataType().should.equal('mock'); }); }); }); }); |
This approach works because by requiring the modules up front using Require and its default context, we rely on the standard Require logic to ensure the modules only load once. By telling Squire to mock the modules, it will not try to load them but will use the mocks provided, the common instances loaded by Require.
In the case of non-AMD libraries that return nothing to the factory function, such as the BlockUI plug-in above, simply requiring it will cause Require to load it. Upon load, the library does its thing (registers itself with jQuery) and that is all that is needed from it. Telling Squire to mock it keeps it from being loaded again in the new context, and because the library doesn’t provide a value, providing null as it mock value to Squire works just fine.
One final item to note is that in defining the mock for jQuery we cannot simply write
injector.mock('jquery', $ ); |
rather we must do
injector.mock('jquery', function() { return $; }); |
The reason for this is that contrary to the Squire documents, the second argument to mock is not always “the mock itself.” The second argument to mock works just like the final argument to define in Require. It may be an object or a function. If it is a function, then Require presumes it to be a factory function that it will invoke in order to get the mock. Since both jQuery and classes (i.e. constructors) are functions, they must be wrapped in factory in order not to be invoked as a factory.
]]>Originally, to accomplish this, I was following the comprehension example on the CoffeeScript site. With this approach, my code would look something like this:
input = [ value: 1 name: 'a' , value: 2 name: 'b' ] convert = (objectIn) -> id: objectIn.name value: "#{objectIn.value}" output = (convert(obj) for obj in input) |
This simple example takes an array of input objects and from them produces an equivalent array of output objects where the input “name” property becomes the “id” property in the output and the “value” property is transformed from a number to its string equivalent.
The annoying thing about this approach is the need to define conversion functions for each conversion. I was thinking, boy, wouldn’t it be nice if I could just use a regular for loop where I can put a whole block of transformation code into its body and assign the for loop “results” to the output? But for loops of course don’t return results.
Or do they? This is CoffeeScript after all and “everything is an expression.” Moreover, CoffeeScript is very good at just working the way you want it to (except when you forget the fat arrows of course).
So I tried the following:
input = [ value: 1 name: 'a' , value: 2 name: 'b' ] output = for obj in input id: objectIn.name value: "#{objectIn.value}" |
And it works. Now why isn’t this documented anywhere?
]]>Mostly, when I am using git, I am following the git flow approach to things. However, I don’t generally install the git flow tool. I am fine with doing things manually from the command line. In fact I think any developer should have to learn how to do git flow without the tool first. Its like learning to code in notepad before installing an IDE. But, I digress.
The issue with git-flow is that when you are merging, first you do a rebase of your current branch onto the target branch (git rebase target) followed by a non-fast-forward merge. What this means is that you have to checkout the target branch and then merge your working branch into it: git checkout target && merge working-branch –no-ff.
This is annoying. If I am on my working branch I just want to do git rebase target && git merge-to target, especially if the name of my current branch is long, which it often is.
So I did some googling and found a stack overflow article on the topic. There were several approaches. I liked Dmytrii Nagirniak’s the best. It uses git’s aliases. I didn’t know git had aliases before this. Indeed they are a bit more powerful that bash aliases, so I tend to think of them more as macros.
In any event, I slightly modified his solution and it works great for what I want. Just add the following to your .git/config:
(If the [alias] section header is already present, just add the definition to the end of your list of aliases.)
[alias] #merges the current branch into the specified branch (i.e. reverse of merge). Returns to the current branch if -r specified. merge-to = "!f() { export tmp_branch=`git branch | grep '* ' | tr -d '* '` && git checkout $1 && git merge $tmp_branch && [[ $2 = '-r' ]] && git checkout $tmp_branch; unset tmp_branch; }; f" |
After this I got a little carried away and wrote a few other useful alias.
#Takes to branch names (neither are the current branch) merges the first one into the second one, returning to the current branch. merge-branches = "!f() { export tmp_branch=`git branch | grep '* ' | tr -d '* '` && git checkout $2 && git merge $1 && git checkout $tmp_branch; unset tmp_branch; }; f" #Moves the branch specified to the hash, branch or tag specified. move-branch = "!f() { export tmp_branch=`git branch | grep '* ' | tr -d '* '` && git checkout $1 && git reset --hard $2 && git checkout $tmp_branch; unset tmp_branch; }; f" |
To clarify, the NBehave behavior is that if I have some test setup (some “givens”), “when” I perform my test action, this is usually followed buy multiple “then” post conditions to be tested. NBehave (and I think to be fair most BDD frameworks), stop evaluating post conditions after the first failing one is encountered.
Doesn’t this presume that there is some order dependency between the post-conditions, such that if a prior post condition failed, the rest of the post-condition tests are invalidated? I see no reason to make this assumption. Even if it is the case in some scenarios that post-conditions have dependencies on each other, in my experience this is not the norm. By terminating the test early one is simply depriving the developer of additional information that actually might help in resolving the failed condition.
Thoughts? Am I missing something?
]]>To get it all working together, my initial, naive approach was to use the utility to generate the SQL script needed to build out the database and then execute that script as part of the Seed() method of my database initializer. (I was subclassing both DropCreateDatabaseIfModelChanges for my website and DropCreateDatabaseAlways for my automated tests.)
The method to actually execute the script looked like this:
public static void ExecuteSqlSript(Database database, string scriptPath) { var conn = database.Connection; if (conn.State == ConnectionState.Closed) conn.Open(); var fullScript = File.ReadAllText( scriptPath); foreach (var command in Regex.Split(fullScript, @"\bGO\b")) { var cmd = conn.CreateCommand(); cmd.CommandText = command; try { cmd.ExecuteNonQuery(); } catch (Exception e) { throw new ApplicationException(e.Message + "\r\n\r\nCommand: " + command, e); } } } |
This worked great for my first few iterations, until I needed to add a model to the framework to represent some of the data on the aspnet_User table.
Mapping my new User entity to the existing table name was easy. It just required adding the following to my DbContext implementation:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<User>() .ToTable("aspnet_Users"); modelBuilder.Entity<User>() .Property(u => u.Name).HasColumnName("UserName"); } |
This lead to the aspnet_regsql generated script failing because EF now was creating the aspNet_User table before the script ran. So my next step was to hack the script by adding the following just before the code to create the table:
IF EXISTS (SELECT name FROM sysobjects WHERE (name = N'aspnet_Users') AND (TYPE = 'U')) AND NOT EXISTS(SELECT * FROM sys.COLUMNS WHERE Name = N'ApplicationId' AND Object_ID = Object_ID(N'aspnet_Users')) BEGIN --This indicates the presense of a the table --as created by the Entity Framework Code First --My EF schema does no use/create the full table --so just drop it so that the script below will do its job. DROP TABLE [dbo].aspnet_Users END IF (NOT EXISTS (SELECT name FROM sysobjects WHERE (name = N'aspnet_Users') AND (TYPE = 'U'))) BEGIN PRINT 'Creating the aspnet_Users table...' /* Actual CREATE TABLE statement omitted for brevity... |
This was a hack, but this was rapid development of the “just get it working” sort. And it worked great, until I added a new model that referenced a user, like so:
public class Record { public int RecordId { get; set; } public Guid UserId { get; set; } [Required] [ForeignKey("UserId")] public virtual User Recorder { get; set; } [MaxLength(4000)] public string Notes { get; set; } } |
This busted my hack because I could no longer just drop the table. There was now a foreign key constraint that had to be deleted first. While I could certainly patch my hack to drop the key too, with more foreign keys on the horizon, it was obvious that this approach was going to quickly become unmanageable.
The problem was that, especially for my automated tests, I wanted to drop and recreate the database regularly. The right solution, therefore was to somehow execute the aspnet_regsql script after EF created the database itself, but before EF built out any tables. If I could do that, EF was smart enough to just use the existing aspnet_User table.
In my search for a solution, I found this article which described how to create a database initializer that would just drop all the table and recreate them w/o dropping and recreating the database itself. This seems promising but its approach to dropping all the tables didn’t account for foreign keys or any other objects that might need dropped too. Modifying it to do so might be possible but could also become a real maintenance headache. My concern was how complex the code would become to find and drop all dependencies which my code might create against the aspnet tables w/o dropping those that the aspnet_regsql script itself created. It might be easy; it might not. I still felt that simply dropping the whole database and rebuilding it was the best approach. So I set out to find a way to inject some functionality between EF’s database creation and schema build out actions. I posted on the EF forum and got a suggestion to try migrations. That wasn’t a bad idea, but still seemed more complicated than I wanted.
Going back to the blog on custom initialization strategies, I looked harder at the provided code, and googled around for some additional examples of custom strategies and in the end was able to come up with a custom initializer that did what I wanted. It
Without further adue, here is the code:
using System; using System.Data; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Data.SqlClient; using System.IO; using System.Text.RegularExpressions; using System.Transactions; public class CreateDatabaseWithAspNetRegSql<TContext> : IDatabaseInitializer<TContext> where TContext : DbContext { public enum CreationStrategy { AlwaysCreate, CreateIfModelChanged } private readonly CreationStrategy _creationStrategy; public CreateDatabaseWithAspNetRegSql( CreationStrategy creationStrategy) { _creationStrategy = creationStrategy; } #region IDatabaseInitializer<Context> Members public void InitializeDatabase(TContext context) { bool dbExists; using (new TransactionScope(TransactionScopeOption.Suppress)) { dbExists = context.Database.Exists(); } if (dbExists) { if (_creationStrategy == CreationStrategy.CreateIfModelChanged && context.Database.CompatibleWithModel(false)) return; context.Database.Delete(); } CreateDatabase(context); DbInitializer.DoAspNetRegSql(context.Database); CreateTablesForModels(context); Seed(context); context.SaveChanges(); } #endregion #region Private/Protected Methods private static void CreateDatabase(TContext context) { var masterDbConnString = context.Database .Connection.ConnectionString .Replace(context.Database.Connection.Database, "master"); //TODO: Find way to create db in an agnostic way. using (var conn = new SqlConnection(masterDbConnString)) { conn.Open(); using (var cmd = conn.CreateCommand()) { cmd.CommandText = string.Format("CREATE DATABASE [{0}]", context.Database.Connection.Database); cmd.ExecuteNonQuery(); } } } private static void DoAspNetRegSql(Database database) { //TODO: This file name reference is a hack, //need a better way of handling this! ExecuteSqlSript(database, @"C:\Users\Ken\Documents\Visual Studio 2010\Projects\MVCSandbox\_Resources\aspnet_regsql.sql"); } protected static void ExecuteSqlSript (Database database, string scriptPath) { var conn = database.Connection; if (conn.State == ConnectionState.Closed) conn.Open(); var fullScript = File.ReadAllText( scriptPath); foreach (var command in Regex.Split(fullScript, @"\bGO\b")) { var cmd = conn.CreateCommand(); cmd.CommandText = command; try { cmd.ExecuteNonQuery(); } catch (Exception e) { throw new ApplicationException(e.Message + "\r\n\r\nCommand: " + command, e); } } } private static void CreateTablesForModels(TContext context) { var modelBuildoutScript = ((IObjectContextAdapter)context) .ObjectContext.CreateDatabaseScript(); RemoveTableCreationCommandsForTablesCreatedByAspNetRegSql(ref modelBuildoutScript); context.Database.ExecuteSqlCommand(modelBuildoutScript); } private static readonly Regex __aspNetCreateTableCommandFinder = new Regex(@"create table \[dbo\]\.\[aspnet_\w+\][^;]*;"); private static void RemoveTableCreationCommandsForTablesCreatedByAspNetRegSql (ref string script) { script = __aspNetCreateTableCommandFinder.Replace(script, string.Empty); } #endregion #region Public Methods protected virtual void Seed(TContext context) { } #endregion } |