|
 Sunday, May 25, 2008

Intro to Microsoft Unity - Dependency Injection Container

 

Note: A full solution is supplied at the bottom of this post if you would like to download it and run it.

A couple of days ago Matt wrote about the new Unity Application Block. The Unity MSDN article describes Unity as:

The Unity Application Block (Unity) is a lightweight, extensible dependency injection container. It facilitates building loosely coupled applications and provides developers with the following advantages:

  • Simplified object creation, especially for hierarchical object structures and dependencies
  • Abstraction of requirements; this allows developers to specify dependencies at run time or in configuration and simplify management of crosscutting concerns
  • Increased flexibility by deferring component configuration to the container
  • Service location capability; this allows clients to store or cache the container

Designing a software system architecture with loosely coupled components makes life easier in the long run. A few of the benefits of loose coupling are : maximizing testability, modularizing components, and increase the maintainability of the code.

This is a simple introduction into Unity that exemplifies the simplicity of the container setup. I will cover two options for type registration:

  1. Manual Method based type Registration
  2. Configuration file (XML Based) type Registration

 

The Example Application

The application that is included at the bottom of this post is visualized via the class diagram below. This simple application utilizes very simple implementations of the repository, mapper, domain model, data transfer object (DTO) and service layer patterns for example purposes.

The application follows a very simple flow as shown below:

image

 

The console application calls into the Service layer which calls into the repository to get the data which calls into the DB. A domain object is created from the Repository call, which is passed up to the service layer. The Service layer returns a DTO via the DTO Mapper to the parent caller (the console app) and then the console app displays the customer name via a write line call.

None of these layers have any inter-dependent dependencies coded inside of them. I'm using constructor injection to inject dependencies into the calling object.

Once unity is set up, it will find the dependencies and supply them to the program at runtime. Therefore, if I need a ICustomerRepository for the service layer to work properly, Unity will give the Service layer a CustomerRepository instance. Since CustomerRepository inherits from ICustomerRepository Unity is able to make this link (once you've set it up) and supply the proper instance.

Class Diagram

image

 

The Setup & Code

The easiest way to see HOW Unity works is to get into the code. My recommendation is to download the sample below, fire it up in Visual Studio and set some break points to see how the code is interacting. Seeing is believing!

Before Unity can supply your application types at runtime, you have to tell Unity WHAT you want it to supply and where to find it. This can be done multiple ways as described here. Today we will go over manual configuration inside of the console app, and xml configuration.

Manual Configuration

image

The manual configuration that I've utilized here utilizes the fluent interface of the container.

Explanation of code: Here we are telling Unity to register a type. We're saying "If someone requests ICustomerRepository, give them an instance of CustomerRepository. If someone requests ICustomerDTOMapper, then give them an instance of CustomerDTOMapper. ..." and so on.

 

 

Using the Container From Manual Configuration

After you've set up the types of objects the container should resolve, you can then ask the container for a instance of "ICustomerService" and then invoke a method call on it. At this very point in time Unity will give you the CustomerService, and then when the customer service needs a repository Unity will then give it a instance of CustomerRepository, etc. At this point in time, everything is mapped for you behind the scenes. The only thing you have to do is ask for the first object and Unity will walk the dependency graph and fill in the blanks for you (if as long as you've given Unity the proper types it needs).

Here's how to do this in the code:

image

 

 

 

XML Configuration

XML configuration utilizes an external XML file (app.config/web.config) to create its dependency graph. This allows for a lot more freedom in what you would like to do with your app. If you're not happy with a certain version of "ICustomerRepository" you can create a new one, drop the DLL in the bin folder and change this config file to point to the new one and you're done. No recompiling!

In this implementation I'm using the app.config file because this is a Console App for example purposes. The full schema for XML configuration can be found here on the MSDN.

To utilize the XML configuration you'll need to utilize a custom config section. You can do this by placing this code into your config section of your app.config file:

image

Next, you'll need to add the container and type definition as shown below (this is just a snippet, full code is included at the bottom of the post):

image

The container gets its types from the config file at runtime.

Each type is declared in the config file as the "type" of object to find and the "mapTo" defines which object to return when the "type" is requested.

The type definitions are declared as type, assembly.

 

 

 

 

 

 

Using the Container From XML Configuration

To force Unity to use the XML Configuration you have to perform few extra set up steps in the application code as shown below. Essentially you're telling Unity that it's configuration/mappings are stored in a config file. The config section configures the container for you, as shown below.

image

To have Unity resolve an instance, its the same as the manual configuration option above. Here is the same image from above that displays how to do this:

image

 

 

 

 

Conclusion

Overall, using Unity as quite simple for this example. The docs on MSDN were pretty good, however I didn't really like the examples that were contained with the download because they did not show you how to utilize XML configuration as I wanted to. It didn't take but a few minutes to figure out what I needed to do. I think Unity is a decent solution at this time. I plan to investigate further into the depths of Unity to see if it may possibly be an alternative for my favorite container tool, Windsor Container.

 

Download The Code For This Post

FooTheory.UnityExample.zip (~477K)

#    Comments [2] |
 Friday, May 23, 2008

TIP: Utilizing Fluent Syntax with the "Is" Keyword in Rhino Mocks and NUnit

Rhino Mocks and NUnit both have a "Is" keyword, both used for a fluent style of syntax. Unfortunately this causes testing problems when you need to use them together. The .NET compiler can only understand one "Is" keyword at a time. We can't use both unless we full qualify the second one.

Having said that, I've fully qualified the "Is" keyword for Rhino Mocks and NUnit before and I find it clunky and I feel its a code smell to me.

In the figure below an example of a fully qualified "Is" keyword for Rhino Mocks is declared.

1 [Test] 2 public void ExampleTest() 3 { 4 // ... items ommited for brevity 5 6 With.Mocks(mockery) 7 .Expecting(delegate 8 { 9 Expect.Call(databaseMock.GetStoredProcCommand(null)) 10 .IgnoreArguments() 11 .Constraints(Rhino.Mocks.Constraints.Is.NotNull()) 12 .Return(databaseCommandStub); 13 }) 14 .Verify(delegate 15 { 16 IQuery query = ExampleResultQuery.GetInsertResultQueryFrom(someparameter); 17 IDatabaseCommand command = query.PrepareCommandUsing(databaseMock); 18 Assert.That(command, Is.SameAs(databaseCommandStub)); 19 }); 20 }

On line 11, we can see the fully qualified name: Rhino.Mocks.Constraints.Is.NotNull() method called.

This, my friends, is a code smell (IMO).

 

How To Fix

The NUnit testing framework provides a "Iz" syntax helper that VB.NET developers use because "Is" in VB.NET is a keyword.

Since we're using .NET Managed code we can use the Iz keyword and it will achieve the same results as Is did. Therefore we can use the Is keyword in Rhino Mocks and we can use the Iz keyword in NUnit. This saves a lot of key strokes over the course of a day.

Final Example:

1 2 [Test] 3 public void ExampleTest() 4 { 5 // ... items ommited for brevity 6 7 With.Mocks(mockery) 8 .Expecting(delegate 9 { 10 Expect.Call(databaseMock.GetStoredProcCommand(null)) 11 .IgnoreArguments() 12 .Constraints(Is.NotNull()) 13 .Return(databaseCommandStub); 14 }) 15 .Verify(delegate 16 { 17 IQuery query = ExampleResultQuery.GetInsertResultQueryFrom(someparameter); 18 IDatabaseCommand command = query.PrepareCommandUsing(databaseMock); 19 Assert.That(command, Iz.SameAs(databaseCommandStub)); 20 }); 21 }

Please note: Line 12 has the normal "Is.NotNull()" call from Rhino Mocks, and Line 19 utilizes the Iz syntax helper from NUnit.

I find this much easier on the wrist. :)

#    Comments [1] |
 Wednesday, May 14, 2008

Presenting at the Phoenix Arizona Desert Code Camp

phoenixLogo That's right! I will be presenting at the Phoenix Arizona Desert Code Camp on May 31st 2008.

I will be presenting a course on Dependency Injection / Inversion of Control. The time's have not been posted yet but as I find out more information I will update this blog.

I hope to see you there. Click here to sign up for the code camp.

#    Comments [1] |
 Sunday, May 11, 2008

Using iTextSharp To Watermark/Write Text To Existing PDF's

First off, yes, I know there are other tutorials on how to watermark PDF's with iTextSharp. Unfortunately none of them showed me exactly what I wanted to do - which is why I wrote this one.

Currently I'm involved with a project that utilizes PDF's as their main product - a legal document. When I arrived to this client they utilized iTextSharp to "watermark" their PDF's. I've been wanting to get my hands dirty with iTextSharp for awhile now. So I cracked open the code base one weekend to see how they were watermarking the PDF's. After poking around for about 2 minutes I saw how they were performing the "watermarking" and unfortunately it was not the best way to get the job done.

Problems with current implementation:

  • Images were used to write text.
    • Huh? An image with text was "underlain" into the PDF. The image had faded text that when inside of the finished product, looked watermarked. The image would say things similar to "Sample". The entire image looked like this:
    • image
  • The watermark orientation would always end up as Portrait.
    • This was because the watermark was an image and it was created for a portrait and it was coded to never detect the page orientation. If the page was landscape the watermarked page would look like this:
    • image
  • The watermarked text could never be changed.
    • Well, it could be, but it took a code change. The images were kept as resources in the library. So if they needed a new watermark, that meant a code change, testing and a redeploy.

 

So How Do We Fix This? What's the End Goal?

  • We want to be able to watermark the PDF document with Text, not images.
  • The code should detect page orientation.
  • We should be able to watermark the PDF with text that we provide at run time.
Current Document Expected Result
A Non watermarked document A watermarked document (red is below the text)
image image

The Solution

I'm very amazed with iTextSharp's ability to manipulate PDF's. From existing PDF's to new PDF's to content extraction, iTextSharp does it all. The best part about it is... ITS FREE (other than your development time, that is).

I've created a solution which I provide the download link for at the bottom of the post, but for now here's the code that does the dirty work:

 

FooTheoryPdf.cs

1 using System.IO; 2 using System.Text; 3 using iTextSharp.text; 4 using iTextSharp.text.pdf; 5 6 namespace FooTheory.iTextSharpLibrary 7 { 8 /// <summary> 9 /// Example PDF Class 10 /// </summary> 11 public class FooTheoryPdf 12 { 13 /// <summary> 14 /// Method that will utilize iTextSharp to write the <see cref="stringToWriteToPdf"/> to the 15 /// pdf on each page of the PDF. 16 /// </summary> 17 /// <param name="sourceFile">The PDf File</param> 18 /// <param name="stringToWriteToPdf">The text to write to the pdf</param> 19 /// <returns>The bytes of the newly updated PDF with <see cref="stringToWriteToPdf"/> in the pdf.</returns> 20 public static byte[] WriteToPdf(FileInfo sourceFile, string stringToWriteToPdf) 21 { 22 PdfReader reader = new PdfReader(sourceFile.FullName); 23 24 using (MemoryStream memoryStream = new MemoryStream()) 25 { 26 // 27 // PDFStamper is the class we use from iTextSharp to alter an existing PDF. 28 // 29 PdfStamper pdfStamper = new PdfStamper(reader, memoryStream); 30 31 for (int i = 1; i <= reader.NumberOfPages; i++) // Must start at 1 because 0 is not an actual page. 32 { 33 // 34 // If you ask for the page size with the method getPageSize(), you always get a 35 // Rectangle object without rotation (rot. 0 degrees)—in other words, the paper size 36 // without orientation. That’s fine if that’s what you’re expecting; but if you reuse 37 // the page, you need to know its orientation. You can ask for it separately with 38 // getPageRotation(), or you can use getPageSizeWithRotation(). - (Manning Java iText Book) 39 // 40 // 41 Rectangle pageSize = reader.GetPageSizeWithRotation(i); 42 43 // 44 // Gets the content ABOVE the PDF, Another option is GetUnderContent(...) 45 // which will place the text below the PDF content. 46 // 47 PdfContentByte pdfPageContents = pdfStamper.GetUnderContent(i); 48 pdfPageContents.BeginText(); // Start working with text. 49 50 // 51 // Create a font to work with 52 // 53 BaseFont baseFont = BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, Encoding.ASCII.EncodingName, false); 54 pdfPageContents.SetFontAndSize(baseFont, 40); // 40 point font 55 pdfPageContents.SetRGBColorFill(255, 0, 0); // Sets the color of the font, RED in this instance 56 57 58 // 59 // Angle of the text. This will give us the angle so we can angle the text diagonally 60 // from the bottom left corner to the top right corner through the use of simple trigonometry. 61 // 62 float textAngle = 63 (float) FooTheoryMath.GetHypotenuseAngleInDegreesFrom(pageSize.Height, pageSize.Width); 64 65 // 66 // Note: The x,y of the Pdf Matrix is from bottom left corner. 67 // This command tells iTextSharp to write the text at a certain location with a certain angle. 68 // Again, this will angle the text from bottom left corner to top right corner and it will 69 // place the text in the middle of the page. 70 // 71 pdfPageContents.ShowTextAligned(PdfContentByte.ALIGN_CENTER, stringToWriteToPdf, 72 pageSize.Width/2, 73 pageSize.Height/2, 74 textAngle); 75 76 pdfPageContents.EndText(); // Done working with text 77 } 78 pdfStamper.FormFlattening = true; // enable this if you want the PDF flattened. 79 pdfStamper.Close(); // Always close the stamper or you'll have a 0 byte stream. 80 81 82 return memoryStream.ToArray(); 83 } 84 } 85 } 86 }

Then there is a small math library I created to get the angle of the text through some simple Trig.

FooTheoryMath.cs

1 using System; 2 3 namespace FooTheory.iTextSharpLibrary 4 { 5 /// <summary> 6 /// Math library 7 /// </summary> 8 public static class FooTheoryMath 9 { 10 public static double GetHypotenuseAngleInDegreesFrom(double opposite, double adjacent) 11 { 12 //http://www.regentsprep.org/Regents/Math/rtritrig/LtrigA.htm 13 // Tan <angle> = opposite/adjacent 14 // Math.Atan2: http://msdn.microsoft.com/en-us/library/system.math.atan2(VS.80).aspx 15 16 double radians = Math.Atan2(opposite, adjacent); // Get Radians for Atan2 17 double angle = radians*(180/Math.PI); // Change back to degrees 18 return angle; 19 } 20 } 21 }

 

The Results

Utilizing a simple interface:

image

We're able to generate PDF's that are watermarked on an angle from bottom left corner to top right corner.

Here is a screen shot of what the generated PDF looks like:

Clicking the Top button:

image

Clicking the Bottom Button:

image

I'm able to change the message:

image

This will produce:

image

 

Conclusion

I found the iTextSharp quite versatile for working with PDF's. This solution will help you write text to existing PDF's quite easily.

Possible implementations include:

  • Place this into a WCF service to create a watermarking service
  • Leave it as it is, implemented as a class library.
  • Create your own .NET PDF Client that you could sell (I've read somewhere - cant find the source - that a couple third party .NET PDF components are actually written on top of iTextSharp).

While working to accomplish what I have above I found the best reference for iTextSharp was actually the iText Book written by Bruno Lowagie. You can purchase it here on Amazon.com.

And Finally ... While writing this I kept thinking .....

Why would you want to watermark existing PDF's?

There are a few options.

  1. Accountability: Lets say you have a ton of PDF's stored from a long running highly confidential report process and these PDF's are stored nightly/weekly on a certain directory. Perhaps you want to make sure that when a user logs in and accesses one of these highly confidential PDF's you water mark it with the users name on each page. Therefore, if it makes it into the hands of the media, you can see where/who it came from.
  2. Licensing: Perhaps you main product is a PDF. Lets say you're a book publisher and you sell PDF versions of the book or you allow people who have already purchased the hard copy to download the PDF version.  What you can do is force the user to create a profile in order to download the PDF. Usually this also includes some type of security question like "turn to page 435 and give us the last word on the page" in order to validate the user actually HAS the book in hand. Once they are authorized to download the PDF book, you can watermark every page on the book with their name "Licensed to: <FirstName> <LastName>. Let's face it, people are MUCH less likely to give a PDF book away on Torrent or P2P software when every single page has their name on it. It's not the BEST method of licensing, but it works.
  3. Other: Perhaps Company A is acquired by Company B and Company B wants to make sure that all PDF's on Company A's site are amended with the text "Company A is a subsidiary of Company B". What if company A has 15,000 PDF's that they have on their site? Maybe its a resume assistance site that has over 15,000 sample resumes. Are you going to open each PDF and do this by hand? Nope. Not at all. You can intercept the call for the PDF's and then write the text at the bottom before they're delivered to the end user.
  4. The list could go on and on ...

 

Download The Code

FooTheory.iTextSharpLibrary.Example.zip (4.69 MB)

#    Comments [4] |
 Wednesday, May 07, 2008

The Importance of Unit Testing WCF Attributes

Normally unit testing is used to verify that state is being altered as expected and interactions are occurring as expected (state based testing or interaction based testing). We also write integration/functional tests to ensure that layers and components are working together correctly in the overall picture.

While in the field I've noticed that most tests neglect the attributes of the WCF ServiceContract. Shouldn’t these be tested as well? Yes, they definitely should!

You may say .... "OperationContractAttribute  is just an attribute that indicates that this method is part of a service contract in a WCF application, so why do I need to test the attribute?" 

Good question... consider this scenario:

You're the developer on a large enterprise system and you've created a WCF Service that handles processing sets of data. Depending on the parameters, this data can take hours process. Therefore you've decided to implement the "IsOneWay" attribute value on the OperationContractAttribute.

Is One Way explanation:

Use the IsOneWay property to indicate that an operation does not return a reply message.
...
If the IsOneWay property is set to false (the default), even methods that return void result in a reply message. In this case, the infrastructure creates and sends an empty message to indicate to the caller that the method has returned. (Using this approach enables the infrastructure to send SOAP faults back to the client.) Setting IsOneWay to true is the only way to cancel the creation and dispatch of a response message.

 

Why Testing IsOneWay Matters

Now that you've set the IsOneWay value to true in your service, the calling applications can fire off a request and let the service crunch away on the request (remember, in this scenario, it may take hours to complete). This is an expected behavior of your service - having the method return as soon as its sent without waiting for a response message from the service.

Fast forward 4 weeks .... Joe Developer decides to remove the "IsOneWay" value (which in turn changes it to false, which is its default) because its not working for his new application as he expects. Everything works for him now, and he checks in the code to source control. Everything builds on your continuous integration environment. All tests pass, everything looks golden.

The new service updates and application updates get applied to production and almost immediately users start complaining about another line of business application "freezing up" when they click a certain button.

"All of a sudden, when I clicked the <Load Data> button, the application just froze. I just left for lunch and when I came back everything was normal. Now, its doing it again. I'm not sure what's going on. This application sucks."

You check the app logs, event viewers, traces, etc and then realize that the application IS WORKING but it stops for quite awhile at the service call. The weird thing is that the code does not throw any errors, it just takes forever to return from that call. This problem seems to be a performance problem. If you're not careful this problem could masquerade itself as another probelm in your mind:

"Is the network slow?"

"Is the service down?"

"Is it doing a retry?"

"Are all the packets getting transmitted?"

The list could go on and on.

The Reason For the Slow Down in the App

Why is the app performing so poorly at this service call? Because IsOneWay was set to false (default when not preset in the attribute values). The app that was written 4 weeks ago expects IsOneWay set to true so it does not block the current thread waiting for a response from the service call.

Since the call is set the value of IsOneWay is set to false, the application is now hanging.

How To Prevent This

The continuous integration environment should have had a test for this. Either unit test or integration test. Unfortunately it did not, and in most companies I don't see a test for this kind of thing, ever.

To fix this we need to implement a unit test for this attribute. We need to make sure that it is set to TRUE so that we dont break anything.

 

Code

Below is the code to implement the test for the IsOneWay attribute value.

FooTheory.WcfServiceExample.cs  - The service we need to test.

1 using System.ServiceModel; 2 3 namespace FooTheory.WcfServiceExample 4 { 5 [ServiceContract] 6 public interface IFooTheoryWcf 7 { 8 [OperationContract(IsOneWay = true)] 9 void Execute(); 10 11 } 12 }

The Unit Test

FooTheoryWcfContractTests.cs

 

1 using System; 2 using System.ServiceModel; 3 using FooTheory.WcfServiceExample; 4 using NUnit.Framework; 5 using NUnit.Framework.SyntaxHelpers; 6 7 namespace FooTheory.WcfExampleTests 8 { 9 [TestFixture] 10 public class FooTheoryWcfContractTests 11 { 12 private readonly string ONE_WAY_METHOD_NAME = "Execute"; 13 14 [Test] 15 public void Execute_Should_Be_OneWay() 16 { 17 object[] atts = typeof (IFooTheoryWcf) 18 .GetMethod(ONE_WAY_METHOD_NAME) 19 .GetCustomAttributes(false); 20 21 OperationContractAttribute opAttribute = 22 (OperationContractAttribute) Array.Find(atts, 23 delegate(object obj) 24 { 25 if (obj is OperationContractAttribute) 26 return true; 27 return false; 28 }); 29 30 Assert.That(opAttribute, Is.Not.Null, 31 "Could not find the attribute connected to the method that is needed."); 32 Assert.That(opAttribute.IsOneWay, Is.True, 33 "Method should be marked as IsOneWay for Application X"); 34 } 35 } 36 }

Code Explanation

The unit test uses reflection to get the attribute of OperationContract and then it checks to see if its not null and also checks to see value of the IsOneWay property.

 

Conclusion

If either one of these asserts fail, the build will break in the continuous integration environment. This will let the dev's know that something they did broke an expectation on the service contract. Catching this type of problem early in the cycle can help immensely. Not only does it save time, but it saves money in both dev time as well as end user time.

If you don't catch this early on, you could be calculating the costs of lost time of a couple of devs as well as numerous end users who are using the dependent application(s). If you're using this Service in a SaaS approach, you could really been in some hot water with those clients that utilizing your service. No one wants to use a service that is unreliable.

So, remember, test early and test often! Get those WCF Attributes under test!

#    Comments [0] |
 Tuesday, May 06, 2008

Upgraded Personal Blog to DasBlog 2.x

I upgraded my personal blog site (where all this same content is cross posted) with DasBlog 2.0.7 in about 10 minutes flat. It was super easy. I spent the next 30 minutes verifying things worked still.

Update: Weird. Cross posting works fine. Something is has definitely gone awry.

Unfortunately I can't log in now, but I CAN log in from Windows Live Writer. I must have something mucked up in the web.config or security configuration. Gotta go figure that out this weekend. Until then, live writer it is.

#    Comments [0] |
 Monday, May 05, 2008

Software Development: Greeenfield vs. Brownfield

Jargon, slang, blah blah blah... So what's the difference between the two? Its quite simple actually, so lets dive right into it.

Greenfield Development

Greenfield Greenfield Development happens when you start a brand new project, as in, clean slate development. No legacy code lying around, no old development to maintain. You're starting afresh, from scratch, from a blank slate, with no restrictions on what you're doing (other than business rules of course).

The definition from the Wikipedia Entry states: "In software engineering jargon, a greenfield is a project which lacks any constraints imposed by prior work."

It's also described as "File --> New Project/Solution".

In my experience, a true Greenfield projects is quite rare in line of business applications. Almost always you have to interact with some legacy code at some point in time and perform integrations with that legacy code that impose limitations on your development.

Examples of Greenfield Development

  • Building a new E-commerce solution from the ground up
  • Implementing a new rules engine for your company from the ground up.
  • Rewriting an old app in a new language (maybe C++ to C#) but not utilizing any of the old code other than for business rule reference
  • A new startup wants application X Built. Application X has never been built before, therefore Application X is a greeenfield endeavor

 

Brownfield Development

Brownfield Brownfield Development happens when business decide to develop/improve upon an existing application infrastructure. As an upgrade is implemented into an existing solution, the development is said to be Brownfield.

The Manning "Brownfield Application Development in .NET" book defines Brownfield development as: "A Brownfield application is a project, or codebase, that was previously created and may be contaminated by poor practices, structure, and design but has the potential to be revived through comprehensive and directed refactoring."

I'm not sure if if completely agree with the definition above, but I do think its close. Brownfield Software Development is about working with previously created code. To me, it does not mean that the code is legacy, as the term "legacy code" has a completely different connotation as soon as you've read Feathers "Working Effectively with Legacy Code". I believe Brownfield development can occur on an excellent foundation of code. What if the application that we need to enhance has 90% code coverage? Does that mean that the code is poorly structured and hard to update, and contaminated? No, not at all. I'd argue that it doesn't have a contaminated structure with that much code coverage, but then again, it depends on the code and how it was architected.

Examples of Brownfield Development

  • Adding a new feature to software that was developed last year
  • Altering the functionality of the code to enhance the performance of an application
  • Upgrading the codebase to expand the working set of functionality across the board.

 

Conclusion

My experience in the field varies between Greenfield and Brownfield. I've spend 1/2 my career behind the desk at companies as an employee. I've spent the other 1/2 as a consultant. I've seen quite a few Greenfield projects, and I've seen even more Brownfield developments. As a standard employee at any company, I'd say that 50% of what I did was Greenfield (and I know that's not normal from talking to my colleagues), and 50% was Brownfield. From a consultant standpoint, I normally perform Greenfield development. But as of lately I've been on a Brownfield engagement that's spanned many months. I'd have to say at this point in time I'm doing about 70% Greenfield and 30% Brownfield as a consultant.

What's the norm? I can't say, I'm no governing source of this info, but from what I've seen in the field it looks like to be ~20% Greenfield and ~80 Brownfield.

Does it matter which type of development you're involved with? Yes and No. If you want to make great software, you can do that in both areas. If you want to run with the latest and greatest technology in the field, perhaps you should consult a little more. But in the end, what really matters is that you have passion for what you do regardless of the type of development you're doing.

#    Comments [1] |
 Thursday, May 01, 2008

By Far, The Coolest Flash App I've EVER Played With

I've played with a lot of Flash applications, hell, I've written a TON of them. I was one of the very few developers developing/integrating PHP/MySQL/Flash 5/MX/ActionScript programming that I know of at the time. Here's a few links to some of them I built that are still online.

Unfortunately the Internet archive doesn't keep track of flash movies that well otherwise I'd link the SUPER COOL ones (tons of animation based upon user input and data from the persistence store) I did that had TONS of integration. I had a ton of other ones that I've done but either the band or label went under so they're not online and I don't have a portfolio site for them (although I should for historical purposes). Between my stints at Lava Records, Atlantic Records, Dreamworks Records, Nitro Records and the now defunct Grave 9 Records I wrote a lot of PHP/MySQL and Actionscript. Thank god those days are over. Oh .NET how I love thee... anyway... enough geek talk.

Why The Best Ever?

One of my favorite hip-hop artists, Atmosphere, released a new album called "When Life Gives You Lemons" (You Paint That Sh!t Gold). Seriously, its a great album, but this isn't a music review site - its a technology blog so lets back to topic Felker ...

With the release of this album they released a web app that allows users to "Tag The World" (www.paintitgold.com) which in effect lets the user take a screen capture (through the use of a Flash App) by typing in a URL and then you can use a set of tools to tag up the site of your choice.

You can use spray paint, stencils, different colors, sizes, markers, etc, its cool. I literally lost about 2 hours on this site. I got sucked in this evening. That NEVER happens, so when it does I'm completely amazed at how the site did it. After being on the net for 10+ years I thought I'd seen it all, NOPE. This is cool. I've seen some "Paint" sites before, but this one got me sucked in.  The other sites that implemented the "paint" feature were very MSPaint. Lets face it, MSPaint, well... sucks. Its great to grab screen shots, but then again, why aren't you using Paint.NET?

Anyway, that aside here's what I did to my site. Honestly, I must have created over 50 of these before I just said screw it and decided to save it for the heck of it.

(click the image to see a larger version on the actual site)

The real awesome-ness is that the spray paint has pressure, and you can size the stencils, rotate them, and just go crazy in general. Afterwards,  you can submit your "masterpiece" (if you want to call it that - mine definitely is ... look at my new digs on my picture above - *haha*) to a gallery on the site. Afterwards it gives you code to post your masterpiece on your blog (which is how I got it to my site).

Conclusion

Take a look at how simple it is to use this site.

I mean it, literally look at how easy it is to use. You don’t have to be a computer genius to get it to work. It just works. This site has a GREAT UX and its fun as hell. There is music playing in the background. You get to tag up a site, hell, just have fun, and you can save your drawing in the end. Every single Web 2.0 designer that wants to make a fun compelling app can learn something from this site. The saying goes "Don't Make Me Think". Not only did this site NOT make me think, it led my hand to allow me to escape into their site (and literally escape reality for a couple of hours).

The only thing I wish they had was a "undo" feature that worked as I expected. From what I could find it you could only "clear the canvas" ... but... then again... this is a hip hop site and the hip hop culture embraces graffiti, and in a true blank canvas sort of way this site embraces the graffiti element beautifully. In the real world you can't just "undo" a line of paint on a wall (or train for that matter). :) You have to keep on going whether you like the piece or not. Its art. :)

Final Thoughts

Kudos to the developers of this site, great job guys.

Heuer lets create a version in Silverlight that blows this one out of the water. :)

#    Comments [4] |