in

Redwerb

Tools, tips, and techniques for software developers.

Redwerb

Tools, tips, and techniques for software developers.
  • Searching for members by display name in Community Server

    If you are looking for a tutorial on how to search for members by display name in Community Server 2008, look no further. After many hours of working on it, I have finally figured out the magic combination and I'm willing to share it with the world. This article is intended for developers with ASP.Net and SQL experience.

    Step 1: Add fn_GetProfileElement to your database

    This is a database function that I've previously blogged about. Just copy the code from my Getting Profile Properties from ASP.Net and Community Server post and run it in Query Analyzer. We'll be using this function in the next step.

    Step 1: Update cs_vw_Users_FullUser

    cs_vw_Users_FullUser is the view that is used to query for the list of users. We'll want to add the users display name to this view.

    The display name is stored in the PropertyValuesString field in the aspnet_Profile table. This field can contain a lot of different pieces of data. The table contains another field called PropertyNames that is used to find the value. The users display name is stored in a field called commonName.

    Here is the code to recreate the view:

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER OFF
    GO
    
    ALTER View [dbo].[cs_vw_Users_FullUser]
    as
    
    SELECT
        U.AppUserToken,
        U.Email,
        U.ForceLogin,
        U.IsAnonymous,
        U.LastAction,
        U.LastActivity,
        U.MembershipID,
        U.UserAccountStatus,
        U.UserID,
        U.UserName,
        U.CreateDate,
        UP.AllowSitePartnersToContact,
        UP.AllowSiteToContact,
        UP.EnableAvatar,
        UP.EnableDisplayInMemberList,
        UP.EnableDisplayUnreadThreadsOnly,
        UP.EnableEmail,
        UP.EnableHtmlEmail,
        UP.EnableOnlineStatus,
        UP.EnablePrivateMessages,
        UP.EnableThreadTracking,
        UP.EnableFavoriteSharing,
        UP.IsAvatarApproved,
        UP.IsIgnored,
        UP.ModerationLevel,
        UP.Points as UserPoints,
        UP.PostRank,
        UP.PostSortOrder,
        UP.PropertyNames as UserPropertyNames,
        UP.PropertyValues as UserPropertyValues,
        UP.PublicToken,
        UP.SettingsID,
        UP.TimeZone,
        UP.TotalPosts,
        dbo.fn_GetProfileElement('commonName', AP.PropertyNames, AP.PropertyValuesString) as DisplayName
    FROM
        cs_Users U (nolock)
        INNER JOIN cs_UserProfile UP (nolock) ON U.UserID = UP.UserID
        LEFT JOIN aspnet_Profile AP (nolock) ON U.MembershipID = AP.UserID
    

    Step 3: Create a custom SqlCommonDataProvider

    We need to customize the SqlCommonDataProvider in order to change the fields the search uses. You will want to create this class in a separate project. I attempted to do this in the App_Code directory in the web project but couldn't get past this error:

    Critical Error: DataProvider

    The dataprovider class "CommonDataProvider" could not be loaded.

    There might be some way to get past this error and keep the code in the web project, but I found that creating a separate assembly worked.

    Once you've got your class, you will want to copy the code in SqlGenerator to it. Community Server didn't exactly make mods easy, they use many non-overridable methods. All the methods in SqlGenerator are static and this is the code you need to modify which is why we are copying it.

    In BuildMemberQuery, look for this line...

    sb.Append(" and ( UserName LIKE @SearchText OR Email LIKE @SearchText ) ");

    and change it to this...

    sb.Append(" and ( DisplayName LIKE @SearchText OR UserName LIKE @SearchText OR Email LIKE @SearchText ) ");

     

    Now override GetUserList, copy the code from the base method, and call your new BuildMemberList instead of the SqlGenerator version.

    command.Parameters.Add("@sqlPopulate", SqlDbType.NText).Value = BuildMemberQuery(query, this.databaseOwner, false);
    command.Parameters.Add("@sqlPopulateCount", SqlDbType.NText).Value = BuildMemberQuery(query, this.databaseOwner, true);
    

    Compile the assembly into the web projects bin directory.

    Step 4: Update communityserver.config

    Now that we've got our new CommonDataProvider, we need to tell Community Server to use it. The setting for this is in communityserver.config which is in the root of the web project. Look for CommonDataProvider and replace the node with this (use your assembly name of course)...

    <add
      name = "CommonDataProvider"
      type = "MyNamespace.MySqlCommonDataProvider, MyCustomAssembly"
      connectionStringName = "SiteSqlServer"    
      databaseOwnerStringName = "SiteSqlServerOwner"
    />
    

    You can download the project and config file for this from my downloads section.

    Download - Custom Community Server Common Data Provider

    Step 5: Upload and enjoy

    If you've followed all the steps, you should now be able to search for users based on their common or display name. If you are having difficulty, make sure you check out the sample project in the downloads section.

  • Mono 2.0 released

    Apparently Mono 2.0 has been released today. I'm a bit surprised that I only saw a single article on the Redmond Developer website about it.

    For those that don't know, Mono is a version of .Net that will run on Windows, Linux, and Mac. Although Mono provides their own C# and VB.Net compiler, it can also run code compiled by Visual Studio without any changes, though there are some compatibility issues so not all code will work (such as an pinvoke calls).

    The 2.0 release of Mono is essentially .Net 3.5 minus 3.0 (no support for WPF, WCF, or WF). A couple of the nice new features in this version include support for WinForms and Xml document processing which apparently was missing in the previous release of Mono.

    If you're interested in learning more about Mono or downloading it, here's a link to their website - Mono. I have not personally used Mono, but it's nice to know that the option is available.

  • Getting Profile Properties from ASP.Net and Community Server

    If you are interested in getting the extended attributes from Community Server or ASP.Net membership, I've created a SQL Server database function that might help. I got the idea from another database function that's floating around the Internet (sorry, I don't know who to credit), but I had a little difficulty getting that one to work (I had the wrong version of another dependent function) so I rewrote it without the dependency.

    Here's an example of using it (the code for the function is below the example). This example will return a list of all the users in Community Server along with some profile information.

    SELECT  u.UserID, 
            u.UserName,  
            dbo.fn_GetProfileElement('MyCsProperty', up.PropertyNames, up.PropertyValues) AS MyCsProperty,
            dbo.fn_GetProfileElement('MyAspProperty', p.PropertyNames, p.PropertyValuesString) AS MyAspProperty
        FROM cs_users u
            LEFT JOIN cs_UserProfile up ON (up.UserID = u.UserID)
            LEFT JOIN aspnet_Profile p ON (p.UserID = u.MembershipID)
    


    CREATE FUNCTION [dbo].[fn_GetProfileElement]
    (
        -- Add the parameters for the function here
        @name NVARCHAR(100),
        @keys NVARCHAR(4000),
        @values NVARCHAR(4000)
    )
    RETURNS NVARCHAR(4000)
    AS
    BEGIN
        -- If input is invalid, return null.
        IF  @name IS NULL
                OR LEN(@name) = 0
                OR @keys IS NULL
                OR LEN(@keys) = 0
                OR @values IS NULL
                OR LEN(@values) = 0
            RETURN NULL
    
        -- locate FieldName in Fields
        DECLARE @pos AS INTEGER
        DECLARE @endPos As INTEGER
        DECLARE @valueStart AS INTEGER
        DECLARE @valueLength AS INTEGER
    
        -- Find the starting position of the key.
        SET @pos = CHARINDEX(@name + ':S:', @keys, 0)
        IF @pos = 0 RETURN NULL
    
        -- Find the starting position of the value.
        SET @pos = @pos + LEN(@name) + LEN(':S:')
        SET @endPos = CHARINDEX(':', @keys, @pos)
        SET @valueStart = CAST(SUBSTRING(@keys, @pos, @endPos - @pos) AS INT)
    
        -- Find the length of the value.
        SET @pos = @endPos + LEN(':')
        SET @endPos = CHARINDEX(':', @keys, @pos)
        SET @valueLength = CAST(SUBSTRING(@keys, @pos, @endPos - @pos) AS INT)
    
        RETURN SUBSTRING(@values, @valueStart + 1, @valueLength)
    END
  • Beware of the Dangers of Visual Thinking

    I've been reading The Back of the Napkin by Dan Roam and it's a great book on visual thinking. He provides some structure to common problem solving skills that involves drawing. However, I found a video where Kermit the Frog shows the dangers of this kind of visual thinking.

    Kermit and friend demonstrates the dangers of visual thinking.

  • Red Gate Buys .Net Reflector

    Apparently Lutz Roeder has sold Reflector to Red Gate. Red Gate has said they plan on keeping a free version available. Red Gate has a lot of great development tools, such as ANTS Profiler and SQL Prompt. It will be interesting to see what they do with Reflector (I'm hoping for a Visual Studio add-in that allows you to debug into assemblies where you don't have source code :)).

    Lutz's announcement

    Red Gates announcement

    New download page for Reflector

  • Introducing Visual Studio Project Zipper Shell Extension

    Download VS Project Zipper

    I am releasing a beta version of VSProjectZipper. This tool will allow you to right-click on a Visual Studio project or solution in Windows Explorer and zip it up and, if desired, email it to somebody.

    VSProjectZipperScreenshot

    Zipping a project works exactly as you would expect. VSProjectZipper reads the project file and creates a zip file that mirrors the directory structure for the project.

    However, if you zip up a solution, VSProjectZipper will create it's own directory structure. Basically the sln file is in the root of the zip file and each project has it's own directory. Solution items are also included and placed into directories. Just to reiterate, it doesn't matter where projects or solution items are on the local file system, the zip file will create it's own directory structure for them.

    The installer also adds a shortcut to your start menu to configure it. There are a number of options that you can change.

    VSProjectZipperConfigScreenshot

    Before you get too excited, you should remember that this is just a beta and there are many known (and I'm sure unknown) issues. Here are the issues that I know of (at least remember at the time of writing this :):

    • Limited testing. I only tested on a single, very simple VB project and a moderately complex C# project and solution as well as a single, simple installer project.
    • Project references are not copied. If you reference an assembly, that assembly is not included in the zip file. This could give compiler errors in the extracted project.
    • Hint paths are not removed or modified. This could also give compiler errors on the extracted project.
    • Test projects can have compiler errors upon extraction. If an accessor is created for a MS test project, you will get compiler errors.

    I'm sure there's plenty more errors as well, but it seems to have worked ok for my BizArk project. I started getting bored with this project so I figured I had better release it before I decided to stop working on it.

  • BizArk updated to 1.0.1

    I've made a number of updates to the BizArk framework for another project that I'm also releasing today (stay tuned).

    New features:

    • New API for SharpZipLib. I didn't like how you had to work with streams and how the zip directory structure was built, so I created an API that hopefully makes it easier.
    • Email API. I created a simple API for sending email using the MAPI32 MAPISendMail function (no need to allocate/deallocate memory!). Supports To, CC, BCC, attachments, subject, body, and either direct send using the users email client or display the users email client.

    Updated components:

    • You can now save and restore a CmdLineObject from an xml file.
    • CmdLineObject can be displayed in a PropertyGrid. Base properties are not browsable.
    • Added ConvertEx.IsEmpty. This method determines if a value is empty. A value is empty if it is null, DBNull, or matches a MinValue, MaxValue, or Empty static field on the class (except for char which checks for '\0'. You can register empty values for any type by calling ConvertEx.RegisterEmptyValue.
    • Added ArrayExt.RemoveEmpties. This method removes empty elements in an array based on ConvertEx.IsEmpty.
    • Many other changes as well...
  • Introducing the BizArk Framework

    For a hobby, some people watch or play sports, others collect or build things. Not me. I code. I spend a large amount of my personal time (time when I'm not at work or with my family) either reading about, playing with, or writing software (it's one of the reasons I continue to write this blog even though I have few actual readers).

    Because of this, I have decided to create a framework that I will share with anybody that wants to use it. I am calling this framework the BizArk framework (if you didn't get it, BizArk is short for business architecture). You can read a full description on the BizArk Framework page.

    This initial release only includes a few things, such as command-line argument parsing, splash screen management, and some extension methods and is really more of a library than a framework. I do plan on adding to this framework, but I don't have any kind of road map or even goals for it.

    I am licensing it under the WTFPL software license. This license allows you to do Whatever The F*** you want with it. I don't really care how people use it, I'm just doing it for fun. Some day I might make it an open source project, but no real plans of that for now.

  • Copyrighting Source Code

    image Do you copyright your source code? Sorry, trick question. If you write source code, it is automatically copyrighted. According to the U.S. Copyright Office; "Copyright is secured automatically when the work is created."

    Before you read this article I feel I should mention that it is essentially a summary of Copyright Office Basics on the United States Copyright Office website. When I decided to write about copyrighting I searched for articles on it. I found a few good ones, but this one covered everything (at least everything I wanted to know) and is a highly reputable source as well (who knows copyrights better than the United States Copyright Office?). Wikipedia also has a pretty good article on it if you want more to read.

    So, back to source code copyright. The general description of works that can be copyrighted do not include source code, however, the document does have this to say about it:

    These categories should be viewed broadly. For example, computer programs and most “compilations” may be registered as “literary works”;

    You are not required to place any notice of copyright in your source code (since March 1st, 1989). However, adding a notice provides additional legal protection against copyright infringement (potentially increased penalty if infringed).

    So what constitutes legal notice? Here is the relevant text from the article:

    The notice for visually perceptible copies should contain all the following three elements:

    1. The symbol © (the letter C in a circle), or the word “Copyright,” or the abbreviation “Copr.”; and

    2. The year of first publication of the work. In the case of compilations or derivative works incorporating previously published material, the year date of first publication of the compilation or derivative work is sufficient; and

    3. The name of the owner of copyright in the work, or an abbreviation by which the name can be recognized, or a generally known alternative designation of the owner.

    Example: © 2006 John Doe

    For source code, since © is hard to type and can sometimes cause problems in source code, I recommend using the word Copyright:

    Example: Copyright 2006 John Doe

    Of course when you write code for a company, the copyright owner is the company. If the code is contracted to another company, it is a work-for-hire and the hiring company gets the copyright (unless specified otherwise in the contract, so read carefully).

    So where should you put your notice? The guidelines only suggest that it must be placed to “give reasonable notice of the claim of copyright.” For source code, this has traditionally been placed at the top of every source file as a comment.

    Compiled code should also be protected. I'm not sure about other languages, however .Net provides an assembly level attribute for copyright. If you use the standard project templates for Visual Studio, there should be an AssemblyInfo file that contains all the assembly attributes, including the AssemblyCopyrightAttribute. At least in VS 2008, you can also get to it through the Assembly Information button in the project properties (Application tab). If anybody out there knows, I would be interested in learning how other languages add copyright notice to compiled code.

    Once created, your copyright will be good for 70 years after your death. If the copyright owner is a company, the copyright is good for "95 years from publication or 120 years from creation, whichever is shorter."

    The role of a software license is to allow others to use your copyrighted material. If you are interested in reading about software licensing, check out Jeff Atwood's article, Pick a License, Any License, on Coding Horror.

  • VS 2008 and .Net 3.5 SP1 Beta

    If you haven't heard the news yet, Microsoft has released a beta of a service pack (SP1) for Visual Studio 2008 and .Net 3.5. I'm not planning on installing the beta any time soon, but I am looking forward to this SP. It looks like it will have some performance improvements, especially for launching .Net WinForm applications (Scott claims up to 40% improvement in startup time) as well as a new installation package for those that don't want the full .Net install.

    If you want to read more about this release, check out these articles (ScottGu's Blog seems to have the most complete description of the features as well as plenty of links out for more information)...

  • Type Conversions

    Note: This article contains a sample project that you can download from the Downloads section of this website - Converting Types Code Example. The code is described towards the end of this article.

    .Net provides many different ways to convert from one type to another. The simplest way to convert one type to another is to use the System.Convert class. This class provides a number of methods to convert to common types such as Boolean, Integer, etc or to any type as long as the type you are converting from implements the IConvertible interface and defines the appropriate conversion.

    You can also use TypeConverters to convert from one type to another. A TypeConverter is a class that defines a bunch of methods that allow you to convert from one type to another. TypeConverters are used extensively in the property browser control (a control that allows you to view properties of a class - used extensively in Visual Studio) and is used primarily to convert from a string to a object and back again. However, TypeConverters can also be used in your code to perform conversions.

       1:  MyTypeConvertTest tcTest = new MyTypeConvertTest("Hello from tcTest");
       2:  TypeConverter converter = TypeDescriptor.GetConverter(tcTest);
       3:  MyTest test6 = (MyTest)converter.ConvertTo(tcTest, typeof(MyTest));
       4:  Console.WriteLine(test6);

    Of course this code only works if you have defined a TypeConverter for MyTypeConvertTest that can convert a MyTypeConvertTest instance to MyTest. Converters aren't too difficult to write, as long as they are simple (they can become somewhat complex when you are writing them for Visual Studio and are using some of the more advanced features).

    Another common method is to provide methods on your class to convert to and from other types. For example, if you wanted to convert a string into a particular type, you might define a static Parse method on your class that takes a string and returns an instance of the class. To convert the object to another type, you can define ToXxx methods on your class (eg, ToBoolean, ToInteger, etc).

    Unfortunately the System.Convert class does not use TypeConverters when doing conversions nor can it handle conversion methods so you are stuck with having to know exactly how the developer intended for the type to be converted (did they implement the IConvertible interface? a TypeConverter? conversion methods?).

    Download Converting Types Code Example

    I have created a sample project that demonstrates using the IConvertible interface, TypeDescriptors, and conversion methods. This project also provides a class that is similar to Microsoft's System.Convert.ChangeType method, but can also handle TypeDescriptors and conversion methods (Microsoft's Convert.ChangeType method only handles classes that implement the IConvertible interface).

  • How Things Work: Events in .Net

    Ever take the time to learn how events work in .Net? They are pretty basic, but unless you have taken the time to discover how they work, they may seem to be a bit like magic.

    Events are a very powerful way to reduce coupling in your application. Events in .Net are based on the Observer pattern identified in the classic Gang-of-Four book, Design Patterns: Elements of Reusable Object-Oriented Software.

    The first part of this article discusses how VB.Net hides some of the complexity of dealing with events. The second part explains how events work in .Net in general.

    What VB.Net Hides From You

    Compared to C#, event handling in VB.Net requires fewer lines of code to both publish and subscribe to events. However, this is because the VB.Net compiler hides the actual implementation from the developer. If you were to look at the code that the compiler generates, you would see that events in VB.Net work pretty very much the same as C#.

    Let's create a couple of simple classes to use as an example. One is called MyPublisher and it defines an event called MyEvent. The other is called MySubscriber which creates an instance of MyPublisher and listens for MyEvent. You can download the example code here (in the download section of this website).

       1:  Public Class MyPublisher
       2:   
       3:      Public Sub ForceMyEvent()
       4:          OnMyEvent(EventArgs.Empty)
       5:      End Sub
       6:   
       7:      Public Event MyEvent(ByVal sender As Object, ByVal e As EventArgs)
       8:      Protected Overridable Sub OnMyEvent(ByVal e As EventArgs)
       9:          RaiseEvent MyEvent(Me, e)
      10:      End Sub
      11:   
      12:  End Class
      13:   
      14:  Public Class MySubscriber
      15:   
      16:      Public Sub New(ByVal publisher As MyPublisher)
      17:          mPublisher = publisher
      18:      End Sub
      19:   
      20:      Private WithEvents mPublisher As MyPublisher
      21:      Public ReadOnly Property Publisher() As MyPublisher
      22:          Get
      23:              Return mPublisher
      24:          End Get
      25:      End Property
      26:   
      27:      Private Sub mPublisher_MyEvent(ByVal sender As Object, ByVal e As EventArgs) Handles mPublisher.MyEvent
      28:          Console.WriteLine("Hello World!")
      29:      End Sub
      30:   
      31:  End Class 

    Pretty basic code, easy to understand, and one of the reasons why I like VB.Net. However, if you really want to understand what's going on, you should open this code up in Reflector. What you see is that the VB.Net compiler hides a lot of the complexity for you. What seems like a simple line of code actually get's broken down into many lines of code.

    NOTE: Reflector shows some code that is automatically generated that doesn't have anything to do with events so I removed it from the examples, as well as it doesn't always generate the code correctly (for example, Reflector starts line 12 in the publisher with RaiseEvent which is incorrect).

       1:  Public Class MyPublisher
       2:   
       3:      Public Sub ForceMyEvent()
       4:          Me.OnMyEvent(EventArgs.Empty)
       5:      End Sub
       6:   
       7:      Public Delegate Sub MyEventEventHandler(ByVal sender As Object, ByVal e As EventArgs)
       8:      Public Event MyEvent As MyEventEventHandler
       9:      Protected Overridable Sub OnMyEvent(ByVal e As EventArgs)
      10:          If MyEventEvent IsNot Nothing Then
      11:              MyEventEvent(Me, e)
      12:          End If
      13:      End Sub
      14:   
      15:  End Class 

    If you are familiar with the way C# handles events, you will notice that VB.Net is compiled into something very similar. IMHO, VB.Net is more elegant in that you can declare the event and the delegate in a single line and you can raise the event in a single line.

    The subscriber is a bit more interesting.

       1:  Public Class MySubscriber
       2:   
       3:      Public Sub New(ByVal publisher As MyPublisher)
       4:          Me.mPublisher = publisher
       5:      End Sub
       6:   
       7:      <AccessedThroughProperty("mPublisher")> _
       8:      Private _mPublisher As MyPublisher
       9:      Private Property mPublisher() As MyPublisher
      10:          Get
      11:              Return Me._mPublisher
      12:          End Get
      13:          Set(ByVal WithEventsValue As MyPublisher)
      14:              Dim handler As MyEventEventHandler = New MyEventEventHandler(AddressOf Me.mPublisher_MyEvent)
      15:              If (Not Me._mPublisher Is Nothing) Then
      16:                  RemoveHandler Me._mPublisher.MyEvent, handler
      17:              End If
      18:              Me._mPublisher = WithEventsValue
      19:              If (Not Me._mPublisher Is Nothing) Then
      20:                  AddHandler Me._mPublisher.MyEvent, handler
      21:              End If
      22:          End Set
      23:      End Property
      24:   
      25:      Public ReadOnly Property Publisher() As MyPublisher
      26:          Get
      27:              Return Me.mPublisher
      28:          End Get
      29:      End Property
      30:   
      31:      Private Sub mPublisher_MyEvent(ByVal sender As Object, ByVal e As EventArgs)
      32:          Console.WriteLine("Hello World!")
      33:      End Sub
      34:   
      35:  End Class 

    In the original code, we declare mPublisher using the WithEvents keyword. What this keyword does is change the field that we defined into a property and creates a new field by prefixing the original name of the field with an underscore. By doing this, when we set mPublisher in our code, what we are really doing is setting the property. This causes the AddHandler/RemoveHandler code to be invoked (if you develop in C#, this is a very useful pattern to follow).

    How Events Work

    In the Publisher class in the above example, MyEventEvent (line 11) is being called as if it were a method, but it is actually what is called a multi-cast delegate. A delegate is basically a reference to a method (in the case of events, this would be the event handler). A multi-cast delegate is essentially a list of delegates that can be called in the same way as a single delegate. Refer to the Code Project article, A Beginner's Guide to Delegates, for a good description of delegates and multi-cast delegates.

    So basically when we raise an event, we are simply iterating through the list of event handlers and calling them one at a time (synchronously). All of the event handlers get called unless one of them throws an exception.

    If you want more control over how events are raised, for example, you want to stop calling additional event handlers when one of them has handled or canceled the event, you can explicitly call each event handler in the list. Let's take our example from above and tweak it so that we are manually calling the methods.

       1:  Protected Overridable Sub OnMyEvent(ByVal e As CancelEventArgs)
       2:      If MyEventEvent IsNot Nothing Then
       3:          For Each handler As MyEventEventHandler In MyEventEvent.GetInvocationList()
       4:              handler(Me, e)
       5:              'If e.Cancel Then Exit For
       6:          Next
       7:      End If
       8:  End Sub 

    In this example we are iterating through the list of delegates (the references to the event handlers) and calling each method in turn. If the event arguments were CancelEventArgs, we could check e.Cancel after calling the delegate and if it was true, we could exit the for loop. You can also use this to add asynchronous event handling to your project (if you do, make sure you document it well!).

  • My Worst Fear

    My worst fear is getting some form of dementia. I think I can handle losing limbs or other serious injuries, but losing my ability to solve problems or communicate would be terrible. The reason I became a software developer was because I enjoy solving problems and my ability to do so is a major way that I define myself.

    The professor of the usability class that I recently started was diagnosed with Parkinson's disease. Parkinson's disease primarily affects the motor skills of an individual. However there are also symptoms that effect the brain, including dementia and short-term memory loss. There is currently no cure for Parkinson's disease. Michael J. Fox suffers from Parkinson's disease.

    Although I am sure the professor is brilliant, he was unable to communicate very effectively due to this disease. One of the symptoms is hypophonia or soft speech. The room was deathly silent for 4 hours during the lecture, any noise (such as changing position in a chair) was a distraction.

    Another symptom that I noticed was short term memory loss.  The professor frequently paused during the lecture, often times in the middle of a sentence, trying to remember what he was talking about. He also went off subject often. Normally this wouldn't bother me, but I was having a hard time paying attention already and I didn't really know what the course was about, so I was often confused about what he was talking about and whether it was part of the course, or something else.

    For a class called Visual Media in Technical Communication, I found it a bit ironic that there was no visual presentation for the class. Perhaps before the professor contracted Parkinson's disease he wrote on the white board or something, however, he sat while he did the lecture (I've never had a professor sit while they did a lecture). Of course, symptoms involving motor skills are the most common symptoms of Parkinson's disease and is probably the reason he sat through it.

    As you can probably imagine, I dropped the class. I feel guilty about dropping the class. It's not the professors fault that he wasn't able to perform his job very well and I'm sure he isn't ready to leave a job that he's been doing for many years. Considering that this is my greatest fear, I am certainly sympathetic to his condition.

    If you are interested in learning more about Parkinson's disease, there are a number of organizations out there. The following list is from the Wikipedia article...

  • 2 down, 1 to go

    Sorry I haven't been posting recently. I've been very busy with work and school and any down time I've had I've been trying to spend with my family and friends or just relaxing .

    I recently finished my second quarter of my user-centered design certificate program and will be starting my last quarter next week. Hopefully I will be able to get back to blogging regularly once I get my certificate.

  • 5 Steps To Managing Your Database In Development

    DBCatI have come across the question of managing databases during development in a number of forums and I thought I would outline the way my company manages the database for our product. We build an ERP (Enterprise Resource Planning) system for manufacturing companies. As you can imagine, the database is an important part of our product.

    1. Each Developer Should Have Their Own Database

    The first thing to mention about our database environment is that every developer has SQL Server installed on their development machine and develops on a local copy of the database. This allows the developer to make changes without having to worry about how it will effect other developers. It also allows them to test using stable data (it's difficult to test your code if other people are making changes to data that you need).

    2. Script Database Changes

    When a developer needs to make a change to the database they make their changes to a script and check it into VSS. These scripts are named in a way to ensure that they run in order. We use the product version (<major>.<minor>.<maintenance>) followed by a script number and then a readable name (eg, 1.0.0.100 My Script.sql). The naming conventions allows us to just process the scripts alphabetically instead of having to create a build configuration file for the order. We leave gaps in the numbering so that we can add scripts without having to rename all of the scripts that come after it. For example, if we add another script to our build after 1.0.0.100 My Script.sql, we would call it 1.0.0-110 Another Script.sql (see screenshot below).

    image

    3. Scripts Should Only Run Once

    In order to prevent a script from running multiple times, we keep track of what scripts have been run in the database. The table is fairly simple, the key field being the name of the script (the name of the file without the extension).

    Our table looks something like this (we actually have more columns, but these are the most interesting ones):

    image 

    Before a script does anything interesting we make sure that it has not been run yet by checking this table. If it has been run, it should just exit gracefully. The sql for this looks something like this:

    DECLARE @ScriptName NVARCHAR(255) 
    SET @ScriptName = '1.0.0.100 My Script' 
    
    IF (SELECT COUNT(*) FROM VersionHistory WHERE ScriptName = @ScriptName) > 0
    BEGIN
        PRINT 'Script ' + @ScriptName + ' has already been run.'
        RETURN
    END 
    
    PRINT 'Run script ' + @ScriptName + '.' 
    
    INSERT INTO VersionHistory (ScriptName, StartTime)
        VALUES (@ScriptName, GETDATE()) 
    
    -- Your SQL here. 
    
    UPDATE VersionHistory
        SET EndTime = GETDATE()
        WHERE ScriptName = @ScriptName

    Once a script has been released to production it should never be modified (not all of the developers at my company agree with me on this point). This makes testing the script much simpler. Of course, if there is a bug in the script, you need to fix the bug, but you should do that in another script.

    There are a couple of different options you can pick from to fix a bug in a script, the one you choose will depend on the severity of the bug.

    1. If the bug is easily correctable the simplest solution would be to leave the buggy script alone and create another script to hotfix it.
    2. If the bug is not easily correctable (eg, it irretrievably destroys data) you should remove the script from the installation process and replace it with a corrected script with a new name (just add 1 to the order; eg, 1.0.0-101 My Script.sql). This new script is not intended to fix the error for people that have already run the original script. If the buggy script was already run on the database, the new script should report an error.

      If customers have already run the bad script and are unable to rollback their database (perhaps the bug wasn't noticed until months later), you will probably need to create another script for those customers. This script should only run if the bad script was run. If it hasn't, it should exit gracefully.

    4. Script Objects Separately

    There are some database objects that can easily be recreated without having an impact on data such as stored procedures, functions, views, etc. We place each one in a separate file so they can be easily maintained.

    During the build process we place them all in a single file per type (eg, a single script for all stored procedures). This ensures that they are run in the correct order (we place them in order based on dependencies to other objects). It also makes it easier to manually upgrade databases when necessary (it's easier to run a single script then a hundred or more).

    5. Create Your Database With Your Scheduled Build

    We have a nightly build process that creates the database. The build basically grabs a copy of the database from the previous release to production and runs the latest version scripts on it. When we release a new version of the product, the scripts are removed from the current branch in source control so that the script directory only contains scripts for the current release.

     

    We have recently released version 8.1 of our product and have been using this process for many years. Although there may be better ways of managing your database while in development, this process has worked well for us.

More Posts Next page »
Copyright Brian Brewder, 2007. All rights reserved.
Powered by Community Server (Non-Commercial Edition), by Telligent Systems