<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6751365918386830778</id><updated>2012-02-02T00:32:53.446-05:00</updated><category term='Usablity'/><category term='SaaS'/><category term='SDS'/><category term='SSO'/><category term='SQL Data Service'/><category term='ASP.NET'/><title type='text'>yoshi's blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://yoshiwatanabe.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://yoshiwatanabe.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Yoshi Watanabe</name><uri>http://www.blogger.com/profile/03731104553539964402</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://3.bp.blogspot.com/-66FJjmDtg2g/TZO-uymWyfI/AAAAAAAAAIs/l0p3a0U-hSs/s220/myprofilepic.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>14</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6751365918386830778.post-7320997870260890353</id><published>2009-09-04T11:47:00.003-04:00</published><updated>2009-09-04T12:13:54.251-04:00</updated><title type='text'>Remove unused code! The simplest rule to follow</title><content type='html'>If your codebase contains anything unused, be it a class, enum, method, property, or even commented out old code, just get rid of it!&lt;br /&gt;&lt;br /&gt;Before applying any adavanced programming techniques like OOP, just follow this simple rule. In other words, before even considering being funcy with virtual methods, Adaptor design pattern, or having a religious war over naming convensions, just make sure the code base contain only and exactly the "live" codes. If not, leave the whiteboard there and go back to the desks!&lt;br /&gt;&lt;br /&gt;This is a simple programming principle, which is extremely easy for everyone to understand, yet often not being followed up with.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6751365918386830778-7320997870260890353?l=yoshiwatanabe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yoshiwatanabe.blogspot.com/feeds/7320997870260890353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6751365918386830778&amp;postID=7320997870260890353' title='68 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/7320997870260890353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/7320997870260890353'/><link rel='alternate' type='text/html' href='http://yoshiwatanabe.blogspot.com/2009/09/remove-unused-code-simplest-rule-to.html' title='Remove unused code! The simplest rule to follow'/><author><name>Yoshi Watanabe</name><uri>http://www.blogger.com/profile/03731104553539964402</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://3.bp.blogspot.com/-66FJjmDtg2g/TZO-uymWyfI/AAAAAAAAAIs/l0p3a0U-hSs/s220/myprofilepic.jpg'/></author><thr:total>68</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6751365918386830778.post-91867288805491856</id><published>2009-04-13T12:26:00.022-04:00</published><updated>2009-05-15T16:09:04.738-04:00</updated><title type='text'>Building Saas application in .NET</title><content type='html'>&lt;span style="font-size:130%;"&gt;&lt;span style="font-size:180%;"&gt;&lt;br /&gt;Take advantage of ASP.NET single sign-on&lt;/span&gt; &lt;/span&gt;&lt;br /&gt;If your application is going to be comparmentalized into multiple sections, consider using third domain (sub-domain) such that you have&lt;br /&gt;&lt;br /&gt;http://foo.myapp.com&lt;br /&gt;http://bar.myapp.com&lt;br /&gt;&lt;br /&gt;then make sure to enable cross-sub-domain SSO by writing the ASP.NET forms authentication cookie against "myapp.com" domain (as against a specific sub-domain such as "foo.myapp.com" or "bar.myapp.com"). This provides extension points for additional ASP.NET web applications while using the same login sessions.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Consider using third-party single sign-on integrations&lt;/span&gt;&lt;br /&gt;Try not to build your own identify server. That is: do not implement your own "login" page that takes password that you manage. You want to stay away from that. Instead, use external identity servers including Windows Live!, Yahoo BBAuth, OpenID, etc. This is a win-win for developers as well as users.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Use XML schema-driven business objects&lt;/span&gt;&lt;br /&gt;After many tries with different approaches, I am convinced that using XML Schema (XSD) with tool generated C# wrapper is the best way to capture business objects. For any new web application, I create a folder called "Entities", and I create three files:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;mybusinessobjects.xsd&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;mybusinessobjects.cs&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;generate.bat&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;mybusinessobjects.xsd will contain all of the data type definitions of the application's business objects. For example, if your application is about student enrollment process, then you will define Studen, Course, Semester, etc. in this XML schema.&lt;br /&gt;&lt;br /&gt;mybusinessobjects.cs is not manually created but created by running XSD.exe tool, that takes XML schema file and produces a C# class definitions. generate.bat is for running XSD.exe and it looks like this&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;xsd.exe mybusinessobjects.xsd /n:MyApp.Entities&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;By executing this line, you will easily get C# object representations of all of the things you defined in mybusinessobjects.xsd, placed in the namespace, "MyApp.Entities"&lt;br /&gt;&lt;br /&gt;These tool-generated C# classes are in-memory "storage" for your business objects, and they can be serialized to XML (and deserialized from XML) very easily.&lt;br /&gt;&lt;br /&gt;This serializability between XML and C# is very convenient and flexible. For example, you can write UI that takes C# object model and set it to DataSource of ASP.NET Repeater control. Or, you can deserialize it to XML and pass it through XSLT to produce another XML, which can be consumed by an existing code. It opens up possibilities to working with your business objects.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Use XML to communicate with Database&lt;/span&gt;&lt;br /&gt;After many attempts to use DataSet in ADO.NET, I am settled with this approach. The idea is to use very stable stored procedure interface, and use XML as input and output parameters, and all variations are captured in XML input/output. For example, many of the stored procedures have the same signature of:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;sp_foo(userId, languageId, xml)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;which returns string (which is xml output)&lt;br /&gt;&lt;br /&gt;Note: there will be some stored procedures that must deviate from this pattern&lt;br /&gt;&lt;br /&gt;With this interface, you can easily build Data Access layer that can be used by Business Logic layer to update data and retrive data to/from database.&lt;br /&gt;&lt;br /&gt;The stored procedure has to be written such that it can take incoming XML and parse it to obtain necessary inputs for the procedure, and be able to form XML output. (Luckly, DBA I work with is very good at this that I don't need to know how its done exactly...)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Use SQL Data Services&lt;/span&gt;&lt;br /&gt;This is another approach for solving data storage needs for a SaaS application. Instead of your maintaining database for your self, completely offload that task to cloud computing. Though I have not used it for commercial development project, I am convinced that SQL Data Services provides sufficient data storage capabilities to web-based application. The benefit is clear: you do not need to maintain your own database tier in your data center (and if you use Azure, where you host your ASP.NET application, then you don't need data center all together!); you pay as much as you use so it is cost-effective.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Use YUI (Yahoo! UI) for your page development&lt;/span&gt;&lt;br /&gt;I have used YUI for both work and hobby and works great. It gives you browser neutrality right from the beginning. Let these experts at Yahoo! to solve browser compatibility issues and just focus on solving your own problem. YUI can be a bit tricky to use in ASP.NET, but many of the components in YUI can be used easily in simpler cases.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Use HttpHandler for AJAX server&lt;/span&gt;&lt;br /&gt;It is possible, and often done, to use regular ASP.NET pages (.aspx) to implement server-side logic that returns XML (or JSON) output to a client-side script. Howerver, it makes more sense to implement such server-side logic using HttpHandler, which is more efficient than ASP.NET pages, and fits well with the model of "client script (UI) - server logic (BLL)". Essentially, client script is acting as user interface, and if you follow strict sepration of UI and Logic, then your server-side logic should not have anything to do with UI, such as page controls. HttpHandler is nothing but an end-point responding to an Http request, where returned output may not necessarily HTML but XML, JSAN, image, document, etc.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Enable Google Analytics right away&lt;/span&gt;&lt;br /&gt;No further discussion on this. Just do it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Pay attentions to security from the beginning&lt;/span&gt;&lt;br /&gt;With web application, you want to start with "locked" down application instead of you lock it down as you go by. Read up "cross-side scripting" and "SQL injection" first and make sure we have no holes for that. Compile a list of Query string being passed around, Cookies saved to the user's machines, input fields that user can type in, and make sure each item is being evaluated to ensure that these cannot be exploited.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Build exception and error handling infrastructure&lt;/span&gt;&lt;br /&gt;First thing you have to do is to define "application exceptions" at your Business Logic layer. Any Business Logic has an error condition that is created because of "user". For example, with Student Enrollment application, if one of the business rules states that "You cannot sign up for a class unless pre-requisites are completed", then you have an exception. Yes, UI can try to make sure that it will never be in such condidtion, but who knows? Business logic layer should NOT rely on UI does good job and never create such situation. Instead, Business Logic should throw "application error".&lt;br /&gt;&lt;br /&gt;This is one of the most important use of Exception handling. You will define your own "application exception" that can be presented to the user and "user" can modify his/her behavior to fix the issue. This is in contrast to "system exception" where it is due to system error and not user. For example, if disk space run out and causes IO exception, user can do absolutely nothing to remedy that.&lt;br /&gt;&lt;br /&gt;So, you deal with two large groups of exceptions: Application Exception and System Exception. Now, how do you handle them and where? The answer is: at each page, look at method that make call to Business Logic layer and wrap it around with try block, then create one catch block to handle application exception, and anthor one for system exception. The way you handle two kinds of exception is different: for application exception, tell user why and what user should to do avoid receiving the same exception (example: show message like "You are not allowed to enroll this course because you have not completed HIS101"). In contrast, for system exceptions you want to show something like "A system error encountered. The error has been reported to system administrator. If this problem continues, please contact xxx-xxxx. Error Code: 2231".&lt;br /&gt;&lt;br /&gt;When handling system exception, your catch code must log the error to somewhere (such as text log file or event log). Ideally, you generate a unique Error Code value, and write it to the event log with the detailed error information, and also show it to the end user. This way, when user calls for a help, technical person at our end can locate the related error event log.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Use WF and WCF right from the beginning&lt;/span&gt;&lt;br /&gt;There are features in Workflow Foundation and Communication Foundations that let you implement your application features easily and effectively. WF comes with sequential workflow and state machine workflow that models many real-world workflow. For example, "student enrollment" is a perfect example for sequential workflow that takes multiple input values to produce a result (student has sign up, system accept it, schedule bill, etc.)&lt;br /&gt;&lt;br /&gt;WCF opens up possibilities to "extentions" such as web-service, REST based API, working with additional back-end engines, etc. The boilerplate code for hand-shaking, security, throttling and bufferin, are all taken care of for you.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Engage users as soon as possible&lt;/span&gt;&lt;br /&gt;In another word, engage in Agile software development model. I strongly recommend using User Stories methodology to drive the whole development process. Good applications solve real user problems, and to do so developers need to know what the problems users are facing. Sometimes users don't know how to describe the problems, and/or they may not understand the best way to solve it. The chances are, the application you built today will be ineffective tomorrow and you will have to make constant changes to the application. So, stay small and address core issues first, then present it to the users to see if it is indeed solveing the users problem. Do not waste time working on bells &amp;amp; whistle since users can go without them for a while.&lt;br /&gt;&lt;br /&gt;Integrate with Facebook and other social media as much as possible&lt;br /&gt;Consider creating a Facebook application that provides an interface to your web application. At minimum, Facebook app has iFrame mode where you can show your web application interface embedded in Facebook. Of course, if you can integrate more, that would be nice. Facebook is an organic solution delivery mechanism where solical graph drives the distribution of solutions. If your application solves a problem for one Facebook user, then chances are, it will be useful to other Facebook users, and the initial "case" of one user solving his/her problem can proliferate to other users with similar problems. Forget the classic "you come to our website and sign up to get good stuff" model.&lt;br /&gt;&lt;br /&gt;That's it for now...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6751365918386830778-91867288805491856?l=yoshiwatanabe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yoshiwatanabe.blogspot.com/feeds/91867288805491856/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6751365918386830778&amp;postID=91867288805491856' title='263 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/91867288805491856'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/91867288805491856'/><link rel='alternate' type='text/html' href='http://yoshiwatanabe.blogspot.com/2009/04/building-saas-application-in-net.html' title='Building Saas application in .NET'/><author><name>Yoshi Watanabe</name><uri>http://www.blogger.com/profile/03731104553539964402</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://3.bp.blogspot.com/-66FJjmDtg2g/TZO-uymWyfI/AAAAAAAAAIs/l0p3a0U-hSs/s220/myprofilepic.jpg'/></author><thr:total>263</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6751365918386830778.post-2584910155325190343</id><published>2009-03-31T11:18:00.002-04:00</published><updated>2009-03-31T11:39:32.194-04:00</updated><title type='text'>How to program well (part 1 of n)</title><content type='html'>Be sure to clearly define "programming interface" of your function.&lt;br /&gt;&lt;br /&gt;Writing a function is a simple part of programming in any language yet it is an essential part of programming and having good functions are very important to produce high quality software. I've seen too many pooly written functions and decided to document what not to do and what to do.&lt;br /&gt;&lt;br /&gt;When I say, pooly written function, these are functions with no clear "interface contract". Here, I am not talking about what is inside of the function (ie. implementation). I actually don't care about implementation (well, it should work, but it is really up to programmer to implement the function however he/she sees appropriate). It is more about "interface".&lt;br /&gt;&lt;br /&gt;There are several important rules about writing good functions&lt;br /&gt;&lt;br /&gt;Function name should have a single action word&lt;br /&gt;A function should do one thing, or a unit of things that is cohernt&lt;br /&gt;Etc..&lt;br /&gt;&lt;br /&gt;However, the issue I see most offten with pooly written functions are lack of clear documentation about its arguments.&lt;br /&gt;&lt;br /&gt;Function arguments should have acceptable values (or domain)&lt;br /&gt;&lt;br /&gt;For instance, if function Foo takes an integer argument, it must clearly state whether 0 is acceptable, negative value is acceptable, whether it has upper/lower limits, etc. Usually function should accompany documetation that describe these details. Amazingly, many professional progammers just don't do this...&lt;br /&gt;&lt;br /&gt;Next, function should "enforce" these domains by using Assertions and throwing Exceptoins. I would recommend setting up both, but sometimes throwing exceptions is sufficient, but not doing either is bad. Without this enforcement, problem would occur down the code stream and it is probably more time consuming to toubleshoot. With enforcement of input values at the function entry, it is much easier to understand what went wrong.... client code deviated from "interface contract" (ie. was never supposed to pass negative value, but it did).&lt;br /&gt;&lt;br /&gt;(I will update this entry)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6751365918386830778-2584910155325190343?l=yoshiwatanabe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yoshiwatanabe.blogspot.com/feeds/2584910155325190343/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6751365918386830778&amp;postID=2584910155325190343' title='23 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/2584910155325190343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/2584910155325190343'/><link rel='alternate' type='text/html' href='http://yoshiwatanabe.blogspot.com/2009/03/how-to-program-well-part-1-of-n.html' title='How to program well (part 1 of n)'/><author><name>Yoshi Watanabe</name><uri>http://www.blogger.com/profile/03731104553539964402</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://3.bp.blogspot.com/-66FJjmDtg2g/TZO-uymWyfI/AAAAAAAAAIs/l0p3a0U-hSs/s220/myprofilepic.jpg'/></author><thr:total>23</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6751365918386830778.post-8350981881284238099</id><published>2009-02-27T10:37:00.021-05:00</published><updated>2009-02-27T11:51:19.829-05:00</updated><title type='text'>SQL Data Services (SDS) Tutorial (Part2)</title><content type='html'>This blog entry is the second part of the SQL Data Services (SDS) Tutorial.&lt;br /&gt;&lt;br /&gt;This article is based on CTP release of SQL Data Services.&lt;br /&gt;&lt;br /&gt;Let's get us started. You begin by opening "SDS Exlorer" from Windows Start menu.&lt;br /&gt;&lt;br /&gt;First of all, delete the text in Query text area so that you can disregard Query stuff for now. (I will discuss Query in future)&lt;br /&gt;&lt;br /&gt;Next, set the address to &lt;pre&gt;https://[your_authority].data.database.windows.net/v1/&lt;/pre&gt; where [your_authority] is the actual authority id yours (read Part 1 of this Tutoria if you don't have one). In this example, I use my test authority called "yoshi".&lt;br /&gt;&lt;br /&gt;&lt;img style="FLOAT: left; MARGIN: 0px 10px 10px 0px" src="http://1.bp.blogspot.com/_Xy7mywGLhQg/SagJ0YNpMHI/AAAAAAAAABk/hoaD5LLrocw/s1600/clear_query_set_authority_address.png" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;Then, click "Get" button.&lt;br /&gt;&lt;br /&gt;&lt;img style="FLOAT: left; MARGIN: 0px 10px 10px 0px" src="http://4.bp.blogspot.com/_Xy7mywGLhQg/SagKKxCKseI/AAAAAAAAABs/_fQnlOHPwaQ/s1600/authority_scope_get_result.png" border="0" /&gt;&lt;br /&gt;You receive information about your Authority (if you get alot more information that what I got above, don't worry. Its called "metirics metadata" and we will cover this later)&lt;br /&gt;&lt;br /&gt;Now, without changing the value in Address, click "Query" button.&lt;br /&gt;&lt;br /&gt;&lt;img style="FLOAT: left; MARGIN: 0px 10px 10px 0px" src="http://3.bp.blogspot.com/_Xy7mywGLhQg/SagLCsBGOdI/AAAAAAAAAB0/eA_p2Hm9OCo/s1600/authority_scope_query_result.png" border="0" /&gt;&lt;br /&gt;This time, you receive an XML element called "EntitySet" with nothing in it. This measn that your Authority is empty. In order to make this Authority useful, we need to add a Container. Let's do that.&lt;br /&gt;&lt;br /&gt;Without changing the Address, Click "Container" button. You will get a template in the main text area. SDS Explorer generated GUID value for you as Id of the new Container, which is about to be created. I changed this to "bookmarks" because that's the application I want to build.&lt;br /&gt;&lt;br /&gt;&lt;img style="FLOAT: left; MARGIN: 0px 10px 10px 0px" src="http://2.bp.blogspot.com/_Xy7mywGLhQg/SagMCQrSikI/AAAAAAAAAB8/sRBhRGKg-hg/s1600/prep_create_container.png" border="0" /&gt;&lt;br /&gt;When you are happy with the name of Container, click "Create" button.&lt;br /&gt;&lt;br /&gt;As usual, it is not appearent if the requst succeeded or not, so open the "Request/Response" window and check HTTP "Response".&lt;br /&gt;&lt;br /&gt;&lt;img style="FLOAT: left; MARGIN: 0px 10px 10px 0px" src="http://2.bp.blogspot.com/_Xy7mywGLhQg/SagM2o-pNZI/AAAAAAAAACE/TtOniyqSKq8/s1600/after_create_container.png" border="0" /&gt;&lt;br /&gt;The status says "Created" so that's a good sign!&lt;br /&gt;&lt;br /&gt;Now, let's talk about an important concept called "Scope" in SDS. If you look at the Address bar right now, you see:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;https://yoshi.data.database.windows.net/v1/bookmarks&lt;/pre&gt;&lt;br /&gt;This is in the format of:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;https:[your authority id].data.database.windows.net/v1/[your container id]&lt;/pre&gt;... and you are in "container scope". &lt;br /&gt;&lt;br /&gt;Understanding "Scope" is important because all operations you perform using SDS Explorer works within the context of the current Scope. For example, if you make a simple HTTP GET request while Authority is the scope, you will get metadata information about the Authority; while Container is the scope, you will get metadata information about the Container.&lt;br /&gt;&lt;br /&gt;Take a look at the output results of clicking "Get" and "Query" buttons while we are in bookmarks container scope.&lt;br /&gt;&lt;br /&gt;Result of "Get":&lt;br /&gt;&lt;br /&gt;&lt;img style="FLOAT: left; MARGIN: 0px 10px 10px 0px" src="http://1.bp.blogspot.com/_Xy7mywGLhQg/SagOjYBV2FI/AAAAAAAAACM/2QOA1itwiMg/s1600/container_scope_get_result.png" border="0" /&gt;&lt;br /&gt;Result of "Query":&lt;br /&gt;&lt;br /&gt;&lt;img style="FLOAT: left; MARGIN: 0px 10px 10px 0px" src="http://3.bp.blogspot.com/_Xy7mywGLhQg/SagOvv_WGuI/AAAAAAAAACU/BcQDByCpvb4/s1600/container_scope_query_result.png" border="0" /&gt;&lt;br /&gt;You observe some metadata information about my "bookmarks" container, and my container is still empty because I haven't added anything. We will cover working with Container in future. For now, let's validate that our Authority indeed contains my newly created container.&lt;br /&gt;&lt;br /&gt;Go back to Authority scope by either clicking on "Go up" button (looks like a folder icon) in Address bar or manually type in:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;https://yoshi.data.database.windows.net/v1/&lt;/pre&gt;&lt;br /&gt;And then click "Query" button.&lt;br /&gt;&lt;br /&gt;&lt;img style="FLOAT: left; MARGIN: 0px 10px 10px 0px" src="http://3.bp.blogspot.com/_Xy7mywGLhQg/SagP_p2241I/AAAAAAAAACc/9yA2-qJWI74/s1600/authority_scope_query_result_after_container_creation.png" border="0" /&gt;&lt;br /&gt;This time, we get EntitySet with one element called Container. This container is the "bookmarks" container that I just created.&lt;br /&gt;&lt;br /&gt;You have successfully created a Container and now you can do a lot of things with it. I will talk about working with Container in future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6751365918386830778-8350981881284238099?l=yoshiwatanabe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yoshiwatanabe.blogspot.com/feeds/8350981881284238099/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6751365918386830778&amp;postID=8350981881284238099' title='22 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/8350981881284238099'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/8350981881284238099'/><link rel='alternate' type='text/html' href='http://yoshiwatanabe.blogspot.com/2009/02/sql-data-services-sds-tutorial-part2.html' title='SQL Data Services (SDS) Tutorial (Part2)'/><author><name>Yoshi Watanabe</name><uri>http://www.blogger.com/profile/03731104553539964402</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://3.bp.blogspot.com/-66FJjmDtg2g/TZO-uymWyfI/AAAAAAAAAIs/l0p3a0U-hSs/s220/myprofilepic.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_Xy7mywGLhQg/SagJ0YNpMHI/AAAAAAAAABk/hoaD5LLrocw/s72-c/clear_query_set_authority_address.png' height='72' width='72'/><thr:total>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6751365918386830778.post-5952122785739443950</id><published>2009-02-25T08:44:00.039-05:00</published><updated>2009-02-25T11:23:00.253-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Data Service'/><category scheme='http://www.blogger.com/atom/ns#' term='SDS'/><title type='text'>SQL Data Services (SDS) Tutorial</title><content type='html'>This blog entry is for you if you are new to SQL Data Services and want to get started.&lt;br /&gt;&lt;br /&gt;This article is based on CTP release of SQL Data Services.&lt;br /&gt;&lt;br /&gt;I assume that you have:&lt;br /&gt;SQL Data Services account&lt;br /&gt;SQL Data Services SDK installed on your machine&lt;br /&gt;&lt;br /&gt;When you start SDS Explorer from Windows "Start" menu, it looks like this.&lt;br /&gt;&lt;br /&gt;&lt;img style="FLOAT: left; MARGIN: 0px 10px 10px 0px" src="http://4.bp.blogspot.com/_Xy7mywGLhQg/SaVQZjmOezI/AAAAAAAAAAU/cfEf4CCrvhg/s1600/startup.png" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;Without doing anything, just click "Query" button at the lower right corner.&lt;br /&gt;&lt;br /&gt;You will receive a popup window asking User and Password.&lt;br /&gt;&lt;br /&gt;&lt;img style="FLOAT: left; MARGIN: 0px 10px 10px 0px" src="http://2.bp.blogspot.com/_Xy7mywGLhQg/SaVSK1LvtEI/AAAAAAAAAAc/CVJD9qywxfg/s1600/askuserpassword.png" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;For User field, provide the solution name you specified while you were signing up for SDS. You should have also received a password at the same time. Once you get passed authentication, SDS Explorer will tell you that it is "working...", and moment later you should see this.&lt;br /&gt;&lt;br /&gt;&lt;img style="FLOAT: left; MARGIN: 0px 10px 10px 0px" src="http://1.bp.blogspot.com/_Xy7mywGLhQg/SaVWdUZgU0I/AAAAAAAAAAs/rwQcMlKESbA/s1600/query_service_result.png" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;Your output may be different from what I have here, but the idea is the same and simple: you get listing of all of the "Authorities" under "Service" that you have permissions to access.&lt;br /&gt;&lt;br /&gt;You can create as many Autorities as you want, but you cannot delete them (I am not sure if this is a limitation during CTP or permanent policy).&lt;br /&gt;&lt;br /&gt;Next, let's create a new Authority.&lt;br /&gt;&lt;br /&gt;Click "Authority" button, which is one of the buttons under "Template" label, which will give you this screen:&lt;br /&gt;&lt;br /&gt;&lt;img style="FLOAT: left; MARGIN: 0px 10px 10px 0px" src="http://4.bp.blogspot.com/_Xy7mywGLhQg/SaVaxtkGrRI/AAAAAAAAAA0/JlgFdPUlatw/s1600/template_authority_result.png" border="0" /&gt;&lt;br /&gt;At this momenty, you haven't done anything to SDS data center. You are simply preparing for a request to create a new authority. Notice that SDS Explorer generated a GUID value for you as Id of the new authority. You could use this GUID or specify something more user friendly. For example:&lt;br /&gt;&lt;br /&gt;&lt;img style="FLOAT: left; MARGIN: 0px 10px 10px 0px" src="http://3.bp.blogspot.com/_Xy7mywGLhQg/SaVp4jwVa4I/AAAAAAAAABM/63atPZffY1M/s1600/template_authority_result_edited.png" border="0" /&gt;&lt;br /&gt;I changed the Id value to "yoshi" (Note. I have not confirmed this but it appears that Authority Id must be unique within the global namespace. My attemp to create Authority with typical id values like "testauthority" and "authorityexample" fails).&lt;br /&gt;&lt;br /&gt;What you are doing here is to define a XML payload which will be sent to the server using HTTP POST request, which we will see next.&lt;br /&gt;&lt;br /&gt;Once you are happy with the name of the new Authority, click on "Create" button.&lt;br /&gt;&lt;br /&gt;Now you have successfully created a new Authority. Unfortunatley, SDS Explorer doesn't make it obvious that the operation succeeded. In order to get a positive confirmation, you should check the HTTP Request/Response data, which is available in a small window that shows up by clicking "Request - Response" button toward the bottom.&lt;br /&gt;&lt;br /&gt;&lt;img style="FLOAT: left; MARGIN: 0px 10px 10px 0px" src="http://4.bp.blogspot.com/_Xy7mywGLhQg/SaVq8ZM7WGI/AAAAAAAAABU/xym1uVt9oRw/s1600/create_authority_result.png" border="0" /&gt;&lt;br /&gt;The "Request" tab shows you that in order to create a new Authority, SDS Explorer made a HTTP POST request against the "Service"&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;POST https://data.database.windows.net/v1/ HTTP/1.1&lt;/pre&gt;&lt;br /&gt;It passed XML payload that act as input for this operation&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;s:Authority xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt; xmlns:x="http://www.w3.org/2001/XMLSchema"&lt;br /&gt; xmlns:s="http://schemas.microsoft.com/sitka/2008/03/"&amp;gt;&lt;br /&gt;  &amp;lt;s:Id&amp;gt;yoshi&amp;lt;/s:Id&amp;gt;&lt;br /&gt;&amp;lt;/s:Authority&amp;gt;&lt;/pre&gt;&lt;br /&gt;And the "Response" tab shows that the server successfully created the Authority.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;POST https://data.database.windows.net/v1/ HTTP/1.1&lt;br /&gt;Status: Created&lt;/pre&gt;&lt;br /&gt;Now, lets check to see if we will see our new Authority in the list of Authorities available under this Service. You can use the folder-looking icon of Address bar to "go up one level".&lt;br /&gt;&lt;br /&gt;While the address bar contains value&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;https://data.database.windows.net/v1/&lt;/pre&gt;&lt;br /&gt;Click on "Query" button. You should see this now.&lt;br /&gt;&lt;br /&gt;&lt;img style="FLOAT: left; MARGIN: 0px 10px 10px 0px" src="http://2.bp.blogspot.com/_Xy7mywGLhQg/SaVr7QE9rbI/AAAAAAAAABc/bplkQeQJjyU/s1600/authority_was_created.png" border="0" /&gt;&lt;br /&gt;My new Authority called "yoshi" is now available.&lt;br /&gt;&lt;br /&gt;I will write more tutorial on this subject later but with this article, you have seen some of the essential SDS concepts:&lt;br /&gt;* SDS Explorer is a handy tool to work with SDS&lt;br /&gt;* You can Query againt https://data.database.windows.net/v1/"&gt;https://data.database.windows.net/v1/ to retrieve listing of Authorities&lt;br /&gt;* You can add your Authority by making HTTP POST request with XML payload (this pattern is called REST)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6751365918386830778-5952122785739443950?l=yoshiwatanabe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yoshiwatanabe.blogspot.com/feeds/5952122785739443950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6751365918386830778&amp;postID=5952122785739443950' title='314 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/5952122785739443950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/5952122785739443950'/><link rel='alternate' type='text/html' href='http://yoshiwatanabe.blogspot.com/2009/02/sql-data-services-sds-tutorial.html' title='SQL Data Services (SDS) Tutorial'/><author><name>Yoshi Watanabe</name><uri>http://www.blogger.com/profile/03731104553539964402</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://3.bp.blogspot.com/-66FJjmDtg2g/TZO-uymWyfI/AAAAAAAAAIs/l0p3a0U-hSs/s220/myprofilepic.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_Xy7mywGLhQg/SaVQZjmOezI/AAAAAAAAAAU/cfEf4CCrvhg/s72-c/startup.png' height='72' width='72'/><thr:total>314</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6751365918386830778.post-1738202263153387116</id><published>2009-02-09T06:59:00.003-05:00</published><updated>2009-02-09T07:06:22.087-05:00</updated><title type='text'>StringBuilder.AppendFormat vs String.Format</title><content type='html'>I am a bit ashamed of not knowing this until now…&lt;br /&gt;&lt;br /&gt;String.Format()&lt;br /&gt;&lt;br /&gt;Actaully creates an instance of StringBuilder and delegates all its formatting work to AppendFormat() method to the StringBuilder&lt;br /&gt;&lt;br /&gt;So, the following is bad coding:&lt;br /&gt;&lt;br /&gt;&lt;pre style="padding: 4px; border: solid 1px gray"&gt;// creates a string that looks like “item=abc,item=xyz,”&lt;br /&gt;StringBuilder sb = new StringBuilder();&lt;br /&gt;foreach(object obj in myCollection)&lt;br /&gt;{&lt;br /&gt;    sb.Append(string.Foramt(“item={0},”, obj)); &lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;If this loops 1000 times, 1000 StringBuilder instances will be created (calls ctor, allocates memory from managed heap, etc) in the loop&lt;br /&gt;&lt;br /&gt;Instead, something like below would be more efficient&lt;br /&gt;&lt;br /&gt;&lt;pre style="padding: 4px; border: solid 1px gray"&gt;StringBuilder sb = new StringBuilder();&lt;br /&gt;foreach(object obj in myCollection)&lt;br /&gt;{&lt;br /&gt;    sb.ApppendFormat(“item={0},”, obj);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;This uses only one instance of StringBuilder&lt;br /&gt;&lt;br /&gt;From now on, you will see me using StringBuilder.AppendFormat more, except simpler cases (because one line of String.Format is still more readable!)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6751365918386830778-1738202263153387116?l=yoshiwatanabe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yoshiwatanabe.blogspot.com/feeds/1738202263153387116/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6751365918386830778&amp;postID=1738202263153387116' title='114 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/1738202263153387116'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/1738202263153387116'/><link rel='alternate' type='text/html' href='http://yoshiwatanabe.blogspot.com/2009/02/stringbuilderappendformat-vs.html' title='StringBuilder.AppendFormat vs String.Format'/><author><name>Yoshi Watanabe</name><uri>http://www.blogger.com/profile/03731104553539964402</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://3.bp.blogspot.com/-66FJjmDtg2g/TZO-uymWyfI/AAAAAAAAAIs/l0p3a0U-hSs/s220/myprofilepic.jpg'/></author><thr:total>114</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6751365918386830778.post-7773415170943072397</id><published>2009-02-04T16:38:00.003-05:00</published><updated>2009-02-04T16:45:18.395-05:00</updated><title type='text'>You shouldn't blog when your last post is one year ago</title><content type='html'>Wow, my last post was over a year ago...&lt;br /&gt;&lt;br /&gt;Writing blogs require such energy and these days you get to say what you want to say mostly in Facebook and Mixi (my other Japanese only SNS).&lt;br /&gt;&lt;br /&gt;Oh well...&lt;br /&gt;&lt;br /&gt;This blog on blogger is meant for "tech" related posts - I don't want to discuss these stuff with my Japanese friends who are not interested in tech stuff and also they don't read English! Facebook is for English-speaking friends but FB is just not the kind of place to talk about tech stuff (or maybe..)&lt;br /&gt;&lt;br /&gt;Anyway, maybe I start writing more random crap on this blog rather than trying to be too informative, which I have tried and failed so many times.&lt;br /&gt;&lt;br /&gt;OK, see you next year!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6751365918386830778-7773415170943072397?l=yoshiwatanabe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yoshiwatanabe.blogspot.com/feeds/7773415170943072397/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6751365918386830778&amp;postID=7773415170943072397' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/7773415170943072397'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/7773415170943072397'/><link rel='alternate' type='text/html' href='http://yoshiwatanabe.blogspot.com/2009/02/you-shouldnt-blog-when-your-last-post.html' title='You shouldn&apos;t blog when your last post is one year ago'/><author><name>Yoshi Watanabe</name><uri>http://www.blogger.com/profile/03731104553539964402</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://3.bp.blogspot.com/-66FJjmDtg2g/TZO-uymWyfI/AAAAAAAAAIs/l0p3a0U-hSs/s220/myprofilepic.jpg'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6751365918386830778.post-2630525529372502745</id><published>2008-01-30T17:27:00.000-05:00</published><updated>2008-01-30T17:42:40.065-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSO'/><title type='text'>Windows Live ID SSO complete</title><content type='html'>I just implemented Windows Live ID SSO (single sign-on) enabled for our use case project - www.usefulcases.com&lt;br /&gt;&lt;br /&gt;I would say that the framework itself is easy, though I ran into an issue due to a configuration issue on our part (not Microsoft fault)&lt;br /&gt;&lt;br /&gt;The problem I had was that domain was configured to "foward" so the callback, which was made in HTTP Post, got translated to HTTP Get, loosing the "token" from the server during the course.&lt;br /&gt;&lt;br /&gt;I could not get the "token" and had to ask Live ID forum for this *strange* behavior. I got a prompt response for troubleshooting... Of course, it was something we did wrong, so we fixed it.&lt;br /&gt;&lt;br /&gt;If we didn't have the configuration problem then it would have been about 1 hour of work from nothing to a SSO. That's pretty good.&lt;br /&gt;&lt;br /&gt;Here is the basic step (off my memory)&lt;br /&gt;&lt;br /&gt;Go to https://msm.live.com/app/registration.aspx?wa=wsignin1.0 and enter data. Pretty easy stuff. One thing: you need to specify the URL of the callback page. If you use C# sample (see below), it is named webauth-handler.aspx, which you can rename to something else. It can be located anywhere but once you set it, you can't change the registration record (you basically need to re-register, which is easy so not huge deal).&lt;br /&gt;&lt;br /&gt;Once the registration succeeds, you get an app ID value.&lt;br /&gt;&lt;br /&gt;Download the C# sample at from http://www.microsoft.com/downloads/details.aspx?FamilyId=8BA187E5-3630-437D-AFDF-59AB699A483D&amp;displaylang=en&lt;br /&gt;&lt;br /&gt;The sample is a small web app.&lt;br /&gt;&lt;br /&gt;Copy one .cs file in App_Code to your web site's App_Code. This is the library class. Also copy the entire Sample folder to your website. I put it under ~\FM\LiveID folder. FM stands for Federation Management. I intend to add YahooBBAuth, so created a subfolder called "LiveID".&lt;br /&gt;&lt;br /&gt;Open the web.config in the folder you just copied.&lt;br /&gt;&lt;br /&gt;You need to modify a couple of lines: one for app ID (you just got that) and a secrete (that you specified at registration)&lt;br /&gt;&lt;br /&gt;That's it!&lt;br /&gt;&lt;br /&gt;The default.aspx page comes with a iframe that shows the "login" link as well as a code to check for a cookie that would be created if SSO succeeds.&lt;br /&gt;&lt;br /&gt;Login using the "login" link. You get the standard Windows Live ID login screen at Microsoft server.&lt;br /&gt;&lt;br /&gt;When SSO succeeds, the default.aspx will show the "token" value. This value is constant and represents this particular user (or Live ID account, to be precise). &lt;br /&gt;&lt;br /&gt;Now, I should try Yahoo! BBAuth (in fact, I've already obtained application ID. I will write about it later.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6751365918386830778-2630525529372502745?l=yoshiwatanabe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yoshiwatanabe.blogspot.com/feeds/2630525529372502745/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6751365918386830778&amp;postID=2630525529372502745' title='62 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/2630525529372502745'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/2630525529372502745'/><link rel='alternate' type='text/html' href='http://yoshiwatanabe.blogspot.com/2008/01/windows-live-id-sso-complete.html' title='Windows Live ID SSO complete'/><author><name>Yoshi Watanabe</name><uri>http://www.blogger.com/profile/03731104553539964402</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://3.bp.blogspot.com/-66FJjmDtg2g/TZO-uymWyfI/AAAAAAAAAIs/l0p3a0U-hSs/s220/myprofilepic.jpg'/></author><thr:total>62</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6751365918386830778.post-6972987296311903889</id><published>2008-01-30T11:29:00.000-05:00</published><updated>2008-01-30T11:29:54.657-05:00</updated><title type='text'>What is Web 2.0?</title><content type='html'>I think I got it. I am sure I am late to this "hot" topic ;)&lt;br /&gt;&lt;br /&gt;I have been trying to define "Web 2.0" in my own words. Until I do that, I don't feel comfortable even talking about it. People talk about it but rarely, it seems, understand what it stands for, and that included me until now (hopefully).&lt;br /&gt;&lt;br /&gt;First of all, Web 2.0 is "a system that let users build a information mass which creates greater &lt;em&gt;gravity&lt;/em&gt; to attract more information (via visiting users)"&lt;br /&gt;&lt;br /&gt;The essense of gravity is "fundamental forces by which all objects with mass attract each other" as &lt;a href="http://en.wikipedia.org/wiki/Gravity"&gt;wiki articile&lt;/a&gt; says.&lt;br /&gt;&lt;br /&gt;Unlike the physical gravity, in web world it is &lt;em&gt;informational gravity&lt;/em&gt;: information (actually persons who posseses information) are attracted to a mass of information.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In addtion, Web 2.0 is "a system where information mass grows using both user-contributed assets, user-judgements, and user-activity events".&lt;br /&gt;&lt;br /&gt;User-contributed assets are actualy not new to Web 2.0: it is any data user provides explicitly including things like YouTube video, discussion board statements.&lt;br /&gt;&lt;br /&gt;User-judgements are indications of user's opinions, typically in the form of positive or negative feedback against data/information available. It includes "thums up" and "stars" you give to things like blogs.&lt;br /&gt;&lt;br /&gt;User-activity events are completely implicit: if user adds a URL to a bookmark service, its action generates a statement, that becomes information, being broadcasted to other users. The fact that you watch a video in YouTube implicitly contributes to the build up of information - view count is a automatic voting mechanism.&lt;br /&gt;&lt;br /&gt;Web 2.0 efforts should contain some, if not all, of these aspects.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6751365918386830778-6972987296311903889?l=yoshiwatanabe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.google.com/search?hl=en&amp;rls=com.microsoft%3Aen-US%3AIE-SearchBox&amp;rlz=1I7GGLD&amp;q=what+is+web+2.0' title='What is Web 2.0?'/><link rel='replies' type='application/atom+xml' href='http://yoshiwatanabe.blogspot.com/feeds/6972987296311903889/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6751365918386830778&amp;postID=6972987296311903889' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/6972987296311903889'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/6972987296311903889'/><link rel='alternate' type='text/html' href='http://yoshiwatanabe.blogspot.com/2008/01/what-is-web-20.html' title='What is Web 2.0?'/><author><name>Yoshi Watanabe</name><uri>http://www.blogger.com/profile/03731104553539964402</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://3.bp.blogspot.com/-66FJjmDtg2g/TZO-uymWyfI/AAAAAAAAAIs/l0p3a0U-hSs/s220/myprofilepic.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6751365918386830778.post-6166259130293244494</id><published>2008-01-28T18:05:00.000-05:00</published><updated>2008-01-28T18:10:12.070-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Usablity'/><title type='text'>Use established icons</title><content type='html'>People are creative and artistic. When you design a software control/widgets, you may use various graphical represenations (glyphs and icons) to represent certain things.&lt;br /&gt;&lt;br /&gt;When you pick icons for "actions", you should try to pick one that general population are used to. This is even more important if your icon does not accompany any text. (By the way, do not rely on tooltip/popup text for explanation - if something had to be explained, then it is already hard to understand)&lt;br /&gt;&lt;br /&gt;+ and - (plus and minus) signs are established for indicating "expand" and "collapse" actions.&lt;br /&gt;&lt;br /&gt;&lt; and &gt; (left arrow and right arrows) are established for moving "forward" and "backword".&lt;br /&gt;&lt;br /&gt;x is established for "closing" a window/panel.&lt;br /&gt;&lt;br /&gt;etc.&lt;br /&gt;&lt;br /&gt;It is best try not to invent new graphical reprentations.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6751365918386830778-6166259130293244494?l=yoshiwatanabe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yoshiwatanabe.blogspot.com/feeds/6166259130293244494/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6751365918386830778&amp;postID=6166259130293244494' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/6166259130293244494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/6166259130293244494'/><link rel='alternate' type='text/html' href='http://yoshiwatanabe.blogspot.com/2008/01/use-established-icons.html' title='Use established icons'/><author><name>Yoshi Watanabe</name><uri>http://www.blogger.com/profile/03731104553539964402</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://3.bp.blogspot.com/-66FJjmDtg2g/TZO-uymWyfI/AAAAAAAAAIs/l0p3a0U-hSs/s220/myprofilepic.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6751365918386830778.post-5561378232422233563</id><published>2008-01-28T18:04:00.000-05:00</published><updated>2008-01-28T18:04:27.232-05:00</updated><title type='text'>Learning Usability from mini-van</title><content type='html'>One of the important aspects of "software usability" is to minimize the number of user actions such as mouse-click and enterying a key.&lt;br /&gt;&lt;br /&gt;It is obvous that fewer is better, but when and for what feature is it appropriate to make it fewer clicks? Well, you have to figure it out by seeing what users do: what is the goal user is trying to accomplish? Does certain gesture tells us about the user goal?&lt;br /&gt;&lt;br /&gt;I have a mini-van for my family and learned one essence of how to think about user goals. I have a key (obviously) and when I insert the key to door at the "driver's side", if I turn the key once, it opens the driver's door, and if I turn once more, then it opens "all" doors. So, it takes twice to open all doors.&lt;br /&gt;&lt;br /&gt;In contrast, if you insert the key at the passenger's side door and turn once, "all" doors open. Appearently, the similar "door opening" mechanism is configured (programmed?) differently.... why? It's is because the chances are the if someone is opening the passenger's side door, it is likely that a family members are getting to the van. However, if someone opens the "driver's door", it is somewhat more likely that it is just you, driver, who wants to get in.&lt;br /&gt;&lt;br /&gt;These are similar to the number of mouse clicks. If you study the "situations" underwhich your software is used, and if certain gestures strongly indicate certain user goals, then system should be programmed to achieve the goal in the least amount of user actions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6751365918386830778-5561378232422233563?l=yoshiwatanabe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://10.0.0.4:1111/usg/www.panerabread.com/wifi/connected/?bc=3422' title='Learning Usability from mini-van'/><link rel='replies' type='application/atom+xml' href='http://yoshiwatanabe.blogspot.com/feeds/5561378232422233563/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6751365918386830778&amp;postID=5561378232422233563' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/5561378232422233563'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/5561378232422233563'/><link rel='alternate' type='text/html' href='http://yoshiwatanabe.blogspot.com/2008/01/learning-usability-from-mini-van.html' title='Learning Usability from mini-van'/><author><name>Yoshi Watanabe</name><uri>http://www.blogger.com/profile/03731104553539964402</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://3.bp.blogspot.com/-66FJjmDtg2g/TZO-uymWyfI/AAAAAAAAAIs/l0p3a0U-hSs/s220/myprofilepic.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6751365918386830778.post-6565724856979069616</id><published>2008-01-23T19:59:00.000-05:00</published><updated>2008-01-23T19:59:47.220-05:00</updated><title type='text'>Self-testing class</title><content type='html'>I am not sure how popular this idea is. Wikipedia does not have much contents in this topic.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Self-testing_code"&gt;Self-testing code - Wikipedia, the free encyclopedia&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I have always been thinking about effective ways to write classes that can be tested easily. I've tried NUnit, which works just great. One drawback was that it is not easy to test protected methods. &lt;br /&gt;&lt;br /&gt;I've also tried Visual Studio Team System's unit test feature, which also works great. It comes with IDE integration so generating test scheketon is a matter of several mouse clicks. It also supports generating "accessors" that would use Reflection to invoke protected members. However, it is still somehow not of my liking. Besides, I use Visual Studio Developer edition for my personal projects and unit test feature isn't just available to me.&lt;br /&gt;&lt;br /&gt;Then, I started tying out "self-testing code".&lt;br /&gt;&lt;br /&gt;I am still experimenting but it seems to be effective. Here is how you would do it.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class Hello&lt;br /&gt;{&lt;br /&gt;  static Hello()&lt;br /&gt;  {&lt;br /&gt;     #if DEBUG&lt;br /&gt;     // add code to test features of Hello class&lt;br /&gt;     #endif&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public void Foo() { }&lt;br /&gt;  public void Bar() { }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Whenever this class is used, the static constructor runs self-testing code, provided that it was compiled as Debug build.&lt;br /&gt;&lt;br /&gt;The condition can be tweaked to use configuration settings. For example, app.config's appSettings can have a key-value pair: TestHello=true&lt;br /&gt;&lt;br /&gt;That way, we can control the self-test execution independent of build target.&lt;br /&gt;&lt;br /&gt;My projects are small, done by few people (my game is worked on by just me and my friend - and another new project is by four of us). Because of the size of the projects, there is not dedicated QA resource - not that I am pushing the responsibility of testing entirely to QA, but my point is that importance of uint testing increases ever more.&lt;br /&gt;&lt;br /&gt;For such small development environment, self-testing strategy might be OK.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6751365918386830778-6565724856979069616?l=yoshiwatanabe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://en.wikipedia.org/wiki/Self-testing_code' title='Self-testing class'/><link rel='replies' type='application/atom+xml' href='http://yoshiwatanabe.blogspot.com/feeds/6565724856979069616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6751365918386830778&amp;postID=6565724856979069616' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/6565724856979069616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/6565724856979069616'/><link rel='alternate' type='text/html' href='http://yoshiwatanabe.blogspot.com/2008/01/self-testing-class.html' title='Self-testing class'/><author><name>Yoshi Watanabe</name><uri>http://www.blogger.com/profile/03731104553539964402</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://3.bp.blogspot.com/-66FJjmDtg2g/TZO-uymWyfI/AAAAAAAAAIs/l0p3a0U-hSs/s220/myprofilepic.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6751365918386830778.post-731957314526291194</id><published>2007-12-24T11:39:00.000-05:00</published><updated>2007-12-24T11:39:49.164-05:00</updated><title type='text'>Web hosting to VPS hosting</title><content type='html'>I've been wanting to swtich from web hosting to a VPS hosting but cost was always an issue. Well, these days, VPS hosting is pretty cheap and it seems it averages around $50 dollars to entry point level (typically 256MB memory with 5GB diskspace and several hundred data transfer per month).&lt;br /&gt;&lt;br /&gt;Web hosting is so cheap (I was paying about $10/m) so I wan't sure if it is worth moving to VPS hosting. Then I found this service at VPSLAND.COM (I don't work for them) which offer the bare minimum option at $20/m. It comes with 256MB and 5GB disk with 100GB monthly transfer. Another attractive thing about this provider was their "incremental" upgrade options. Other places had coarse upgrade increments: in order to move to the next grade, you go up to $80 bucks or sometimes over $100. VPSLAND gives half-dozen steps with $5 dollar increments. My plan is to start with the bare minimum, and then gradually step up according to the actual pain I experience. That makes more economical sense.&lt;br /&gt;&lt;br /&gt;I signed up for VSPLAND last night at 10PM, and rigth now (at 11AM next day) I received all information I needed to migrate to the their hosting environmenet. I just had a successfull initial "hello" test using index.htm (using IP, not domain name yet)&lt;br /&gt;&lt;br /&gt;For the existing web hosting service, I just had a live chat with a sale rep and he canceled it for me. It was a good provider for web hosting. They just didn't have a VSP hosting option that I was looking for.&lt;br /&gt;&lt;br /&gt;The new provider sent me DNS nameserver information. My registar is domainbank, so I went there and updated two NDS nameserver info.&lt;br /&gt;&lt;br /&gt;Next, DNSLAND sent me IP and login instruction. I started RemoteDesktop and logged in successfully. Great to be able to log into my own server. Now I can do all kinds of fun stuff on this server.&lt;br /&gt;&lt;br /&gt;RemoteDesktop experience is slow, but acceptable. Considering it only has 256MB of dedicated memory, it was not completely unusable. All IIS related services were stopped, so I created a dummy default website folder, and had IIS Default Web to point to it. Then I put a test file there. Accessing from outside worked. Good.&lt;br /&gt;&lt;br /&gt;The next thing was to put an ASP.NET page. I then realized that it only had .NET 1.1 Framework. That wont fly. I need 2.0 environment.&lt;br /&gt;&lt;br /&gt;I haven't migrated to Visual Studio 2008 yet, but plan to do so soon at work. I also need a Visual Studio but can't afford a developer edition, so decided to go with Express edition.&lt;br /&gt;&lt;br /&gt;Downloading Visual Web Developer 2008 Express Edition took me a while... Why Microsoft makes simple download experience so complicated? I just need a file downloaded and start runing it. It was partly due to the additional security measures in Windows 2003 Server and IE 7. You just have to configure it right to get it passed (but without completely negating the usefulness of these security features).&lt;br /&gt;&lt;br /&gt;I thought about installing Visual C# but I decided to wait. I will start with Web Developer, keeping all business logic in App_Code folder for now (I now it is not the best practice).&lt;br /&gt;&lt;br /&gt;.NET framework 2.0, 3.5, Visual Web Developer, and SQL 2005 Express will take up 1.5 GB of disk space. I have only 5GB so I need to be conservative. If I want more, then I need to move to a option which is at $30/m. The one at $25 does not give me more diskspace, but doubles the memory.&lt;br /&gt;&lt;br /&gt;By the way, VSPLAND didn't charge any setup fee, which is good thing too.&lt;br /&gt;&lt;br /&gt;I will post any positive/negative experience with this new hosting provider, but for now, it tooks great.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6751365918386830778-731957314526291194?l=yoshiwatanabe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://vpsland.com/winplans.html' title='Web hosting to VPS hosting'/><link rel='replies' type='application/atom+xml' href='http://yoshiwatanabe.blogspot.com/feeds/731957314526291194/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6751365918386830778&amp;postID=731957314526291194' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/731957314526291194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/731957314526291194'/><link rel='alternate' type='text/html' href='http://yoshiwatanabe.blogspot.com/2007/12/web-hosting-to-vps-hosting.html' title='Web hosting to VPS hosting'/><author><name>Yoshi Watanabe</name><uri>http://www.blogger.com/profile/03731104553539964402</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://3.bp.blogspot.com/-66FJjmDtg2g/TZO-uymWyfI/AAAAAAAAAIs/l0p3a0U-hSs/s220/myprofilepic.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6751365918386830778.post-2746287832101050595</id><published>2007-12-18T15:41:00.002-05:00</published><updated>2008-06-03T18:28:43.872-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SaaS'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='SSO'/><title type='text'>Tips for buidling SaaS (Software as a Service)</title><content type='html'>After building a SaaS solution, I found out about few rules that I should follow when I am engaged with another SaaS.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Build a single website for all customers&lt;/h3&gt;&lt;br /&gt;This was the first mistake I made. I create a model website, I set up a framework to create a clone of the model for each customer organization, with some configuration changes applied to each clone (or instance). Actually, when I designed this, the company was going to sell the product as a premise-based software. So by nature, it had to use "cloning" model.&lt;br /&gt;&lt;br /&gt;Then, the company changed the direction and it decided to go to "SaaS" model, but we never made architectural adjustment to the product. It remained premise-based, and deployed in SaaS way.&lt;br /&gt;&lt;br /&gt;One problem with cloning model is lack of scalability: cloning requires resources as we add more and you will quickly run out of resources like CPU, memory, and network bandwidth. The other problem is maintainance. It is a nightmare for operation stuff to apply patches, for instance, because therea are so many instances to make modifictions to.&lt;br /&gt;&lt;br /&gt;Cloning also prevents us from using any sort of load-balancing strategies, which hurts performance.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Enable ASP.NET session state server from Day 1&lt;/h3&gt;&lt;br /&gt;Another big mistake was to use "in-proc" session state. First, session state should be avoided if possible and use alternative techniques like cookies. If your system has to support session state , then use session state server or SQL database session state server from day 1.&lt;br /&gt;&lt;br /&gt;This forces developers to make any object stored in the session state collection serializable. Making an object serializable is relatively easy step (just declared [Serializable()] attribute at type level) but it helps developer realize that session objects are serialized and deserialized and sent accross a wire to a persistent storage. It, usually, makes developers careful about exessive use of session state facility.&lt;br /&gt;&lt;br /&gt;"in-proc" session state has serious scalability issues too. The state information is store in a process memory, so any subsequent request must be serviced by the same process, which creates process affinity. This means you won't be able to set up effective load-balancing scheme. It also hurts reliability: because session state is in memory and if process dies, all session state disappear.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Don't build separate Admin application&lt;/h3&gt;&lt;br /&gt;It is tempting to build a separate administartion application in a form of WinForm or a separate ASP.NET application. In a way, it clearly draws a line between the product and a supporting system.&lt;br /&gt;&lt;br /&gt;However, introducing additional application to the whole picture causes more administrative headaches: operations stuff need to learn about another application. You would also end up duplicating many logics. For example, you need a separate security scheme, need a duplicate business logic and data access layer hiting the same database. If assemblies are shared, then it is less problematic, but if you write a separte code to hit the same database, then that makes changing database more difficult because two clients need to be updated.&lt;br /&gt;&lt;br /&gt;Instead of creating a separate application, create another set of Actors like Admin, Ops, and Support. And then build a role-based security around the system and scope the capabilities around roles. That way, wheather you are an admin or end-user, you are subject to the same security infrastructure, and you can easily move around capabilities among Actors.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Use Single Sign-On instead of your own Identity server&lt;/h3&gt;&lt;br /&gt;One of the most complex sub-system is the security sub-system that authenticates users. Every SaaS application out there has to have one. It is the most time-consuming sub-system and it has almost zero value to your SaaS offering. So, why waste time and money on it.&lt;br /&gt;&lt;br /&gt;You split Security into Authentication and Authorization. You use Single Sign-on (SSO) to solve the Authentication and you build your own Authorization infrastructure. Often Authorization involves business objects and there is no choice but implement it yourself. On the other hand, authentication is pure infrastructure feature. I would recommend using Windows Live ID, Yahoo! ID, OpenID, etc. You could also implement Federation protocols like WS-Federation and SAML 2.0.&lt;br /&gt;&lt;br /&gt;The time it takes for you to figure out Windows Live ID and Yahoo! ID is much shorter than the time it takes for you to build login system (with remember password, change password, secret question/answer, and all these crap) and test it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6751365918386830778-2746287832101050595?l=yoshiwatanabe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://yoshiwatanabe.blogspot.com/feeds/2746287832101050595/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6751365918386830778&amp;postID=2746287832101050595' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/2746287832101050595'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6751365918386830778/posts/default/2746287832101050595'/><link rel='alternate' type='text/html' href='http://yoshiwatanabe.blogspot.com/2007/12/tips-for-buidling-saas-software-as.html' title='Tips for buidling SaaS (Software as a Service)'/><author><name>Yoshi Watanabe</name><uri>http://www.blogger.com/profile/03731104553539964402</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://3.bp.blogspot.com/-66FJjmDtg2g/TZO-uymWyfI/AAAAAAAAAIs/l0p3a0U-hSs/s220/myprofilepic.jpg'/></author><thr:total>0</thr:total></entry></feed>
