XMLpitstop.com   |  VBnetexpert.com   |  Community Credit  
 
 
Pitstop Search:  
in
 
Sign in | Join | Help
 
 
  Blog
    Home  
 
  Entries By Date
 
<February 2008>
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
2425262728291
2345678
 
 
  Blog Categories
   
 
  Archives
    August 2008 (1)  
    June 2008 (4)  
    May 2008 (2)  
    April 2008 (3)  
    March 2008 (3)  
    February 2008 (5)  
    December 2007 (4)  
    November 2007 (1)  
    October 2007 (3)  
 
  Syndication
    RSS  
    Atom  
    Comments RSS  

February 2008 - Posts

  .NET Flea Market  
 

A Flickr code sample (free hypocrisy included)

So, I was working with a Flickr photoset with thousands of pictures and one day it was decided: "Let's redo the tags to be more descriptive." Now, if you use Flickr, you know it's got a pretty neat web interface, but web applications just aren't really meant for certain things like bulk operations. It would be better to have an offline application that could update the photos. So I created rTagger.

That's not the subject of this post. So, I was writing this program to handle Flickr tags and save them. Now, if you've written applications for Flickr, you know it's got a great .NET API, but some APIs still have you go through a bunch of steps to work with it, and Flickr's API was no different. So i created a class to make it more simple.

That's the subject of this post. I was just trying to think of ideas to post and this one came up. So here you go, the FlickAppAuth class. It uses a Singleton pattern (woo hoo)... kind of. It manages the state of the Flickr object, but really it's a little dumb in that it could return Nothing. Looking at my previous posts about intelligent objects makes this post seem a little hypocritical, but if you've been taking notes, you should know just how to improve it on your own.

So if it's so dumb, what does it do? It basically reduces the code you have to write, puts it all in one place, and gives you a class to copy between projects. There's a couple things the class does for you: Authorization (with persistance) and Deauthorization. Pretty much what you would expect by its name.

So if you wanted auth an application, you would use code like:

If Not FlickrAppAuth.IsFlickAuthorized Then
    MsgBox("You must authorize this application with Flickr.")
    FlickrAppAuth.AuthorizeApp()
Else
...
End If

Too much code?

Then you can use the Flickr object out of the auth object

Dim f As FlickrNet.Flickr

f = FlickrAppAuth.Flickr

Now, the dumb part that I alluded to above is that you have to call the FlickrAppAuth.IsFlickAuthorized method once before trying to get the FlickrNet.Flickr object, otherwise it will be Nothing. I suppose you could call it in the property the first time, but then if it's not authorized, you have to do something about it. Do what?> Throw a custom exception? Return Nothing and test for it back in the main app? I figured what I had was a decent compromise.

So here's the code...

Public Class FlickrAppAuth
    Private Shared flickrApp As FlickrNet.Flickr
    Private Shared flickrAuth As FlickrNet.Auth
    Private Shared flickrFrob As String
    Private Shared flickrToken As String

    ' rTagger key for Anachostic
    Private Const FLICKR_KEY As String = "" ' Get your own
    Private Const FLICKR_SECRET As String = "" ' Get your own

    Public Shared ReadOnly Property Flickr() As FlickrNet.Flickr
        Get
            Return flickrApp
        End Get
    End Property

    Public Shared ReadOnly Property UserID() As String
        Get
            Return flickrAuth.User.UserId
        End Get
    End Property

    Shared Sub New()
        flickrToken = My.Settings.FlickrToken ' Or use your own storage scheme

    End Sub

    Public Shared Sub AuthorizeApp()
        Dim flickrUrl As String

        ' Get Frob    
        flickrApp = New FlickrNet.Flickr(FLICKR_KEY, FLICKR_SECRET)
        flickrFrob = flickrApp.AuthGetFrob()

        ' Calculate the URL at Flickr to redirect to
        flickrUrl = flickrApp.AuthCalcUrl(flickrFrob, FlickrNet.AuthLevel.Write)

        ' Load the URL in the default browser.
        System.Diagnostics.Process.Start(flickrUrl)

    End Sub

    Public Shared Sub DeAuthorizeApp()
        My.Settings.FlickrToken = ""
        flickrApp = Nothing
        flickrAuth = Nothing
        flickrFrob = Nothing
        flickrToken = Nothing
    End Sub


    Public Shared Function IsFlickAuthorized() As Boolean
        Try
            ' Authorize app
            If flickrApp Is Nothing Then
                flickrApp = New FlickrNet.Flickr(FLICKR_KEY, FLICKR_SECRET)
            End If

            If flickrFrob Is Nothing Then
                flickrFrob = flickrApp.AuthGetFrob()
            End If

            ' If we have a cached token, use it
            If flickrToken <> "" Then
                flickrAuth = flickrApp.AuthCheckToken(flickrToken)
                flickrApp = New FlickrNet.Flickr(FLICKR_KEY, FLICKR_SECRET, flickrAuth.Token)

            Else
                ' get a new token (assuming we authed the app already)
                flickrAuth = flickrApp.AuthGetToken(flickrFrob)
                flickrApp.AuthToken = flickrAuth.Token
                flickrToken = flickrAuth.Token
                My.Settings.FlickrToken = flickrToken

                flickrApp = New FlickrNet.Flickr(FLICKR_KEY, FLICKR_SECRET, flickrAuth.Token)

            End If

            Return True

        Catch ex As FlickrNet.FlickrException
            Return False

        Catch ex As Exception
            Return False

        End Try

    End Function

End Class

 
 
 
 

Still kickin'

You know what? I am going to redo my ANSI project. I tested out a couple things and the .NET 2.0 console additions do away with all the crappy Win32 API calls I had to do. So now the basic plan if to have some objects like Form, Label, TextBox, MsgBox, and whatever else. Obviously the forms will store their own state in their child controls. You should be able to overlay, show and hide them.

In the brief test I did, I have a Form object and a Label control. The Form object has an assignable border. See?

The code is pretty manual right now, but I'll clean that up eventually. Maybe I'll even learn how to create a Designer for Visual Studio!

Dim f As New ANSIForms.Form
Dim l As ANSIForms.Label

l = New ANSIForms.Label
With l
	.Text = "Welcome to ANSIForms"
	.ForeColor = ConsoleColor.Yellow
	.Location = New Drawing.Point(15, 2)
End With
f.Controls.Add(l)

l = New ANSIForms.Label
With l
	.Text = "This is going to be alot of fun, I can tell"
	.ForeColor = ConsoleColor.Cyan
	.Location = New Drawing.Point(8, 4)
End With
f.Controls.Add(l)

l = New ANSIForms.Label
With l
	.Text = "Labels work, now to do textboxes and create an ActiveControl concept."
	.ForeColor = ConsoleColor.Cyan
	.Location = New Drawing.Point(2, 5)
End With
f.Controls.Add(l)

l = New ANSIForms.Label
With l
	.Text = "wait, I need to make labels handle text wrapping and honor the size property."
	.ForeColor = ConsoleColor.DarkYellow
	.Location = New Drawing.Point(2, 5)
End With
f.Controls.Add(l)

f.Show()


Console.CursorLeft = 10
Console.CursorTop = 10

Console.ReadLine()

 
 
 
 

Kickin' It Old Skool

I was listening to a CD I made of some old MOD music from Future Crew and I wondered, what ever happened to my old ANSI project? The idea was to create a library of functions and effects to simulate the ANSI displays of yesteryear. I remember I had begun writing it a whlie ago and was pretty well obsessed with it. Then nearing the release of .NET 2.0, I looked at some of the upcoming additions to the .NET console and saw they had expanded it. So I gave up, thinking it would be for nothing, since .NET 2.0 would do everything I was doing.

As it turns out, the .NET 2.0 console doesn't do much of what I was writing. Not that it means I'm going to pick up this project again, but I thought I'd share some of what I was doing. And seeing the code doesn't do it justice, and no one wants to download an EXE to see it, so here you go: a massive 36k WMV file demoing the features I had created by the time I gave up.

As it turns out, I guess this blog disables OBJECT embedding, which makes it a bit hard to show a video. If you really care, you can download the video here.

Now some of the code isn't too bad. It is in .NET 1.1, so I'm not going to post a download or anything. It uses interfaces for borders and "effects", so I can add additional borders to text frames and make new effects, like maybe Scroll, or Popcorn (everything would be displayed lower-case and random letters would become capitalized and return to lower-case. Remember? That stuff used to be SOOOO COOOOOL!

I guess we're all grown up now, so the idea of cyan and magenta text is pretty lame, but some of us long for the simpler days. I was pretty bummed when I loaded the source from VSS that I hadn't implemented a spinning propeller cursor yet. It was four characters in a looped sequence: |/-\

I feel so old.

 
 
 
 

Objective Awareness

I mentioned self-aware objects in my previous post and that got me thinking. And like usual, it's not a new concept, but it's something that I do often and take for granted.

If you have an class and you create a new instance of it, you should assume it has everything it needs to operate. You should not have to tell a Customer object to load the customer's orders, it should know enough to do it on its own. And it should be smart enough to not do it if it doesn't need to. Like, what is up with this code?

Dim c As New Customer
c.Load(customerNumber:=10)
c.LoadOrders()
For Each o As Order In c.Orders
    Debug.WriteLine(o.OrderDate.Tostring("d"))
Next

If you were a new programmer and you didn't know about the LoadOrders method, you'd get nothing. So instead the Customer object should be smart enough to get the orders on its own. Why shouldn't it? It has all the needed data. But it shouldn't get the orders unless asked. Like why load the orders when the code is:

Dim c As New Customer
c.Load(customerNumber:=10)
Debug.WriteLine(c.CustomerName)

So you should have the LoadOrders() method in the Orders property:

Public ReadOnly Property Orders() As CustomerOrders
Get
    If _CustomerOrders Is Nothing Then
    	_CustomerOrders=new CustomerOrders(Me)
	LoadOrders()
    End If

    Return _CustomerOrders
End Get
End Property

First off, notice the property is readonly. You are never going to create the CustomerOrders object and assign it to the Customer object. The Customer object controls the life of the CustomerOrders object. Then, notice there is a private variable holding the customer orders: _CustomerOrders. This variable is scoped at the class level. If you never ask for orders, it remains as Nothing and never gets loaded. Once you ask for orders, it's loaded. The next time you ask for orders, they're already loaded and you have them right away.

I actually keep an isNew variable in my classes so if the object is new, it doesn't even try loading anything, it just creates the new object for me to populate.

That's one example of an object controlling its destiny.

 
 
 
 

Pseudo-code Design

In extremely formal programming environments, early design is done with UML diagrams. The intent is to discuss processes and steps independent of any programming language or final structure. There comes a time, though, that a programming style begins to become evident in the models. Usually this happens at around the design of the sequence diagrams.

In the sequence diagrams, the designer is indicating the objects and the calls that need to be made between objects. Again, this is supposed to be at a higher level than code, but many times it is taken pretty literally.

I'm as guilty as the worst. I try to make the sequence diagram show everything I want done to accomplish a task. It's like writing a code outline. In fact, I write pseudocode before I write the sequence diagram.

Why would I want to write the code before explaining to others how to write the code via diagram? The answer is Microsoft. Well, Microsoft is the inspiration. There isn't much doubt that when Microsoft gives you an API, it typically does a lot for you. One popular example would be the Application Blocks. The data application block compresses many lines of data access code into a single statement. Once you use it, you wonder how you got by without it.

So that's what I strive for in the design of objects. I want them to be simple and clear. I want them to do as much work as possible for the next programmer that comes along. None of this is new. But when you're coding an app, do you ever think about what another programmer would think of your objects? Would they be intuitive enough to use without generating a runtime error?

Sometimes, designing this way breaks the proper design cycle.

For example, you have a use case stating "User looks up customer record and sets user to Inactive." As the programmer, what kind of code would you like to write? I can think of a few different ways:

Dim c As Objects.Customer
c = Objects.Customer.Search("John", "Smith")
If c IsNot Nothing Then
    c.Active = False
    c.save()
End If

Or maybe:

Dim search As New CustomerLookup
Dim results() As Customers
results = search.FindByCustomerNumber(custNum)
Select Case results.length
    Case 0
	Throw New Exception("Customer not found.")
    Case 1
	results(0).InactivateCustomer()
    Case Else
	Throw New Exception("Multiple customer found for customer number.")
End Select

But the point is, you are trying to make the code as easy for the developer as possible. Because change is here to stay. What if you didn't think ahead with something like this? What possible nightmare code could you end up with?

Dim searcher As New Search
Dim results As SearchResults
searcher.Database = My.Settings.dbConnectionString
searcher.Table = "dbo.Customer"
searcher.SearchField = "CustomerNumber"
searcher.ReturnObject = GetType(Customer)
searcher.MatchType = MatchTypes.Exact

results = searcher.DoSearch
If results.ItemCount = 1 Then
    Dim c As Customer = CType(results.ReturnObject(0), Customer)
    c.Active = False

    c.Save(My.Settings.dbConnectionString)
End If

And maybe the flexibility of the "Search" object is great, but there's no way a new programmer could figure out the initialization steps to create a search. Could this have been solved using code design? Maybe. Actually, that example was written spur of the moment and I'm not entirely sure it accurately illustartes my point. You'd have to assume that the Search object used to do one thing and it got enhanced over and over to do everything. That's for another story: objects should know only what they need to.

Here's a different example. Which code seems more logical?

Dim c As New Customer
c.load(customerNumber:=10)
For Each o As Order In c.Orders
    Debug.WriteLine(o.GrandTotal)
Next

or

Dim c As New Customer
Dim co As Orders
c.load(customerNumber:=10)
co = New Orders(c)
For Each o In co
    Debug.WriteLine(o.GrandTotal)
Next

In the first example, Orders is a property on the Customer object, where in the second example, Orders is a standalone object that has to be instantiated with a Customer object.

One of the drawbacks I would visualize is a new developer going straight to the Orders object even though they can't create it directly. The example isn't doing the problem justice. I'm thinking of a deeper object tree where it's not so straightforward to get to an object.

But anyway, I started by talking about design and ended up with a lot of code examples. So let's quickly try to wrap it up and ask: does a UML diagram illustrate these finer points? Can you end up with objects that will get coded like this if you purposely do not think of code while designing? Will your objects be self-aware or will they just be data containers with a bunch of methods to manipulate the data?

The answers lie with the developer.

 
 
 

 
Copyright © . All Rights Reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems