Category Archives: Reviews

Pro ASP.NET MVC Framework Review

Early in my career, when I wanted to learn a new technology, I’d sit in the bookstore aisle and I’d work my way through each of the available books on the given subject.  Put in enough time in a bookstore and you can learn just about anything. I used to really enjoy my time in the bookstore – but times have certainly imagechanged.  Whereas books used to be the only place I could find solutions to my problems, now they may be the very last place I look. 

I have been working with the ASP.NET MVC Framework for more than a year.  I have a few projects and a couple of major deployments under my belt and I was able to get up to speed with the framework without reading a single book*.  With so many resources at our fingertips (podcasts, screencasts, blogs, stackoverflow, open source projects, www.asp.net, you name it) why bother with a book?

Well, I flipped through Steven Sanderson’s Pro ASP.NET MVC Framework a few months ago. And since it is prominently displayed in my co-worker’s office, I tend to pick it up as a reference from time to time.  Last week, I’m not sure why, I decided to read it cover to cover.  Man, did I eat this book up.  Granted, a lot of what I read was review, but it was only review because I had already learned lessons by piecing the puzzle together for myself via various sources.

If I were starting with ASP.NET MVC (or ASP.NET Web Deployment in general) today, the first thing I would do is buy Steven Sanderson’s Pro ASP.NET MVC Framework and read it cover to cover.

Steven Sanderson did such a great job with this book! As much as I appreciated the in-depth model, view, and controller talk, I was completely impressed with all the extra bits which were included.  There a was nice overview of BDD, view engine comparisons, a chapter dedicated to security and vulnerabilities, IoC, TDD and Mocking (of course), IIS deployment options and a nice overview of what the .NET platform and C# offers.  Heck, Sanderson even include bits about webforms!

The book is fantastic and I highly recommend it – even if you think you’ve already got your head around ASP.NET MVC.  By the way, procrastinators may be in luck.  ASP.NET MVC V2 Framework can be pre-ordered.  You might want to jump right into the second edition and find out what Sanderson has to say about MVC 2.

* Actually, I did read through the free bits of Professional ASP.NET MVC 1.0.  But it was just a chapter – albeit a really long chapter.

Why’s (Poignant) Guide to Ruby

You’re familiar with O’Reilly’s brilliant Head First Series, right?  Great.  Then you know how every book begins Book cover of Head First Design Patternswith an explanation of the Head First teaching style and you know the teaching format which Kathy Sierra and Bert Bates developed is based on research in cognitive science, neurobiology and educational psychology and it’s all about making learning visual and conversational and attractive and emotional and it’s highly effective.  Anyway, it’s a great series and you should read every last one of the books. Moving on…

I’ve been wanting to learn more about Ruby and Why’s (Poignant) Guide to Ruby has been on my reading list for a while and there was talk about cartoon foxes and other silliness and I figured Why’s (Poignant) Guide to Ruby probably takes the same imageunorthodox teaching style as the Head First books – and that’s great – so I read the book, in piecemeal, over the last couple of weeks and, well, I figured wrong.

Now having read the book, here’s my take on Why’s (Poignant) Guide – it’s very creative and clever and it does a darn good job of introducing one to Ruby.  If you’re interested in Ruby or simply interested, the online book is worth your time.  If you’re thinking (like me) that cartoon foxes will be doing the teaching, that’s simple not the case.  However, the cartoons and the random stories in the sidebar may serve a purpose. Unlike the Head First books where images and captions are used to further explain the teachings, the cartoons and stories in Why’s Guide serve as intermission and offer your brain a brief moment of rest before the next Ruby concept is explained.  It’s not a bad strategy, but definitely not as effective as the Head First techniques.

 

Assembla – Quick Review

 

UPDATE: Assembla.com has changed their ways.  The bottom line is their free, private spaces hosting option is no longer available.  In my opinion, they still have a valuable service, it’s simply not as great now that I have to pay for it. 🙂

 

A good while back, I commented about SVN Hosting through SVNRepository.com.  Well, I am still using SVN Repository but I came across another option, Assembla, last week and it deserves some attention.

Though many SVN repositories provide an accompanying Trac instance, that’s about all they do.  Frankly, that’s because that’s all they need to do. Assembla is the exception.  It takes hosting one step further.

Assembla is a complete software development tools package offering workspaces to thousands of teams for FREE.  The screenshot below gives you an idea of what is provided.  There’s everything from a SVN, Git or Mercurial repository to a project-specific Wiki and Chatroom.  If you look around, you will even find a Time Tracking application.

image

You may add team members to your Workspace with different privileges as well as establish security settings for non-member access.

image

Creating a space is low friction…just visit the home page, click “Create a new space” and follow the instructions.  The free account includes all of the core functionality and is limited to 200MB of storage.  If the free account doesn’t meet your needs, Assembla does also provide commercial and branded options which include further functionality and support in exchange for cash money.  You can find out more about Assembla plans on their tour page.

I recommend creating a free account and clicking through the tools as Assembla may be a good option for you.

iPhone Firmware Update

For my birthday, back in early July, I received an Apple gift certificate for the exact purchase price of a shiny new version 2.0 iPhone. Since I already own the first generation iPhone and I have a tendency to avoid ridiculously long, seemingly endless lines, I haven’t picked up my present yet.  Actually, the last time I even thought about cashing in my certificate was one week after the iPhone 2.0 launch.  At the time, the nearest Apple Store had multiple rows of chairs lined up outside of the front door.  These chairs, I discovered, were reserved for folks who had previously waited in line but didn’t get to the cashier prior to the product selling out.  I guess the customers were lucky enough to receive a ticket or voucher along with the privilege to wait in line again once the next shipment arrived.  So, I wasn’t even close to getting a new phone a week after launch and I haven’t made it back to the store yet.

What I have done, however, is upgrade my firmware which took roughly as long as some of those poor folks had to wait in line outside the store.  Perhaps I am jumping ahead, but don’t attempt to upgrade unless you have time.  I’m told some upgraded are completed within 30 minutes, but I, unfortunately, have 16GB of storage space on my iPhone and I am using over 90% of it so the backup and restore of my data alone took close to an hour.  That on top of a 218MB download and the upgrade itself makes for a long firmware upgrade.

All things told, I completed the firmware upgrade because I was very interested in playing around with the AppStore and, well, I had nothing to lose.  I will say I have found the upgrade to be of little value at this point.  Yes, I now have Pandora running on my phone which is cool although the app is clunky.   I have experienced the keyboard delays and more crashes (supposedly fixed with the 2.0.1 release which I haven’t installed yet) and sadly my email pulling is far, far, far less reliable now than ever.  In fact, I find myself often times rebooting my iPhone just to resolve issues. 

When I do get around to picking up my new phone, let’s hope everything works a little more smoothly.

Help Docs Using Sandcastle

I am currently on the bench at work waiting for my next assignment to start up in a few days.  Rather than sitSandcastle Logo around, read blogs and listen to podcasts, I’m keeping myself busy by putting together the beginnings of a code library to be shared across our development team.  Yesterday I started the foundation.  I defined the framework, file system layout and basic namespace conventions.  I also created two class libraries and associated test projects to get the ball rolling.  I’m pleased with the way the common library is turning out.

Today, I refactored a bit and then focused on documentation.  Specifically, I generated help file documentation via the XMLSummary comments. I searched around and played with various utilities and ultimately decided on Sandcastle and Sandcastle Help File Builder.

Sandcastle.jpgSandcastle – Documentation Compiler for Managed Class Libraries, created by Microsoft, produces accurate, MSDN style, comprehensive documentation by reflecting over the source assemblies and optionally integrating XML Documentation Comments. Sandcastle works with or without authored comments and supports .NET Framework 1.1, 2.0, 3.0 and 3.5.  Sandcastle is, however, a command line based tool which has no GUI front-end.  That’s where Sandcastle Help File Builder (SCHB) comes in.  SCHB provides a user interface (as well as command line based tools) to facilitate the building of help files in an automated fashion. Both applications may be found on Codeplex.

Sandcastle (really Sandcastle Help File Builder wrapped around Sandcastle) is easy to install and navigate and I was able to quickly integrate into the common libraries’ best practices.  Now when additional code (new library, class, method, etc) is appended to our common code repository, team members simply need to follow the overall folder structure, code library templates/namespaces and update the Help File Builder project which is now in place.

Below are the instructions on how to extend the existing Help File Builder project.  These instructions will be share with my team members though they can easily be altered to create a help file from the ground up:

  1. Download and install Sandcastle and Sandcastle Help File Builder from Codeplex.
  2. Apply XML comments to your code base. 
  3. Navigate to the Build Tab of your project’s properties and do the following:
    • Check XML documentation file
    • Set file name to bin\[mode]\assembly name.xml where [mode] is debug or release. Example: bin\release\MyCompany.Common.Serialization.xml
  4. Compile your assemblies in release mode.   Note: I’m opting to only generate documentation per the assemblies/xml generated in release mode although it doesn’t have to be this way.
  5. Run Sandcastle Help File Builder. The existing Sandcastle Help File Builder project can be found in the following location: MyCompany\Common\MyCompany.Common.shfb
  6. Add your compiled assembly to the SCHB project:
    • Click Add > Browse to the libraries’ bin\Release > Select dll
    • After the assembly is added, the dll and xml files will be listed in the ‘Assemblies to Document’ list box. 
  7. Document the assembly’s namespace by clicking on the ‘Namespaces’ button and editing the summary.
  8. The MyCompany.Common.shfb project is already configured so there’s no need to change any of the project properties. For future reference, all non-default values are highlighted in bold font within the property list. This information is most obvious if you toggle the project properties to display Alphabetically rather than Categorized.Here’s a list of the settings which have been updated:
    • Help Title=MyCompany.Common Class Library
    • HtmlHelpName=MyCompany.Common
    • KeepLogFile=False
    • OutputPath=./
    • PresentationStyle=vs2005
    • SdkLinkType=Index
  9. Generate the help file by clicking the Generate button in the toolbar.
  10. View the help file by double-clicking the MyCompany/common/MyCompany.Common.chm or by opening the file via the SCHB Documentation/View help file menu option.

Again, I found the tools easy to use though I did encounter one gotcha. My file path included a folder named “.NET 3.5”.  I found that Help File Builder didn’t like the naming convention.  Apparently the preceding “.” caused the issue.  Once I renamed the folder to “NET 3.5” everything worked like a charm.

References:

Learning Test Driven Development

I am relatively new to the Test Driven Development (TDD) scene.  Though I have read up on the subject (specifically Test Driven: TDD and Acceptance TDD for Java Developers by Lasse Koskela), my only hands-on experience is limited to a single, 3-month project where I was the lone developer.  All other information gathered on the subject has been through blog entries, podcasts, ramblings and the occasional deCover Imagemo in the office.  Though I believe I have a good understanding of TDD methodologies, I am far from putting this, dare I say, knowledge to practice.  Good practice, that is…

A spike is a term associated with TDD.  A spike is nothing more than quick coding exercise which validates or invalidates an assumption.  Lasse Koskela says it more eloquently:

A spike is a short experiment with the purpose of familiarizing ourselves with the technology, tools, algorithms, and so forth, that we need for solving the problem at hand.  A spike is  a way to make an unknown known — at least to a point where we know whether it’s worth continuing to dig that way or whether we should start looking for another way.

If you are familiar with TDD concepts, you know that spikes offer no value with it comes to testability, maintainability, etc.  They are merely quick prototypes which I find immensely helpful but should not be considered the focal point of TDD.  Well, my first crack at TDD resulted in roughly 70% spikes and 30% actual tests.  Not too good.

There is no doubt in my mind that I always had the best intension to test-code-refactor, but I wasn’t yet familiar enough with TDD to know I was way off course. There was also no one around to put me on the right track (or keep me honest.) Putting my ego aside, I know I could have used some hand-holding when I was starting off with TDD.

Test Driven Development is a discipline.  Like many other disciplines, TDD requires a teacher, student and practice.  The teacher offers instruction and ensures the discipline is practiced correctly.  The good student gathers knowledge and implements under watchful guidance.  In my opinion, TDD is therefore a seemingly good fit for a team which embraces an Agile approach, collaboration, rapid development and testability.   I’m not saying the lone developer with no prior experience with TDD is not capable of learning TDD on their own. I know some are.  I know guys who have done it.  Simply, I am stating that TDD seems most accessible to the mentored developer working with team members who previously adopted the methodology.  To put it another way, I bet Test Driven Development concepts are best learned through practical, hands-on example.

I haven’t given up on TDD yet.  Who wants to hold my hand?

Analyzing Your .NET Code with NDepend

NDepend is a static analyzer that simplifies the management of a complex .NET code base. Architects and developers can analyze code structure, specify design rules, plan massive refactoring, do effective code reviews and compare different versions of the code. The result is better communication, improved quality, easier maintenance and faster development.  Sounds good, eh?

Full disclosure: I received a free pro version of the NDepend from Patrick Smacchia last week along with little encouragement to use the tool and buzz about it if I find it useful.  Patrick’s timing, in fact, could not have been better as just the evening before a colleague of mine was asking for code metric tool recommendations.  Hopefully the review represents me well, but I am thrilled with NDepend and recommend it highly to anyone wanting to get “more familiar” with their code.

As published by Patrick Smacchia

…something difficult in promoting a tool such as NDepend is to educate about what it can bring to your development shop in terms of agility. NDepend comes with a set of innovative features currently not supported by any other .NET tool. I like to think that what tools such as ReSharper or CodeRush are doing to your code at micro level (i.e methods’ body structuring), NDepend does it at macro level (i.e class, namespace, assembly structuring). Hence, as a developer I personally use both kind of tools to automatically control every aspects of the code base I am working on…

Being a big fan of ReSharper, I had high hopes for NDepend.  Knowing my co-worker could use some help finding a good code analyzer and having a free copy of the software dropped in my lap, I had the immediate incentive to dig into the NDepend tool kit…

How to Get Started

Since I wasn’t all too familiar with NDepend, I opted to first gather basic information about the tool and capabilities.  Here’s what I did:

1. I watched two online demos: Getting started and VisualNDepend basics

2. I reviewed three online tutorials: How do I analyze my .NET applications using NDepend?, What does the NDepend report tell me about my code? and I want to go further to have a better control over my code

3. I read a recent NDepend review posted by Andre Loker and previewed Patrick Smacchia’s Blog for his latest comments.

First Impressions

Before even opening the software it was very clear that NDepend was super powerful and, as another colleague of mine recently said, “it can be a mind blower.”  As I am very sensitive to informatiimageon overload, I proceeded simply and cautiously by basically following the steps found in the online demos.  The Visual NDepend 2.9.0 IDE is friendly and somewhat familiar as the start page could be compared to that of Visual Studio.  Here you may create/open projects or analyze/compare assemblies using the provided shortcuts.  Additionally, you are presented with quick links to the online demos and the installers for NDepend Visual Studio and Reflector add-ins. 

imageI opted to analyze a set of assemblies.  After selecting a half dozen assemblies managed within my current application, the assembly analysis is run and then, after a few moments, the results are presented within the VisualNDepend UI. 

Remember my earlier comment about being sensitive to information overload?  Well, if I wasn’t ready for it, the tool’s default display may have knocked me off my seat.  As you can see in the accompanying screen shot, there are many views and the UI is quite busy.  For the experienced user this is great as the numerous windows actually work nicely together.  For a new user, in my opinion, the elaborate UI may be inappropriate — possibly intimidating — especially if the new user really only wants to gather a simple metric like how many lines of code (LOC) make up a specific component.

With this said, the UI can be customized and all the information is very useful once you understand it.  Don’t be intimidated by NDepend even though the first impression can be a “mind blower.”

I clicked around the UI for about 30 minutes and I quickly got a good sense of its power.  Certainly the demos, tutorials and blogs noted above helped lessen my learning curve so I encourage you to follow my footsteps.

Code Query Language (CQL)

What impressed me most about the NDepend is its Code Query Language (CQL).  Per the NDepend site:

NDepend considers your code as a database and you can write some CQL statements to query and check some assertions on this database.

Out-of-the-box, NDepend comes with dozens of queries which fall into varying categories from Code Quality to Test Coverage .NET Framework Usage. 

And NDepend provides the same 82 code metrics to support you in building your own queries!   Here are a few simple examples of what you can do with the CQL:image

1. Which public methods have more than 30 lines of code?
SELECT METHODS WHERE NbLinesOfCode > 30 AND IsPublic

2. Which classes implement System.IDisposable?
SELECT TYPES WHERE IsClass AND Implements “System.IDisposable”

3. Which methods have been refactored recently and is not thoroughly covered by tests?
SELECT METHODS WHERE CodeWasChanged AND PercentageCoverage < 100

On top of that you can enable/disable or even edit the out-of-the-box queries.  For example, if you don’t agree that all static fields should be prefixed with an ‘s_’ change the query to validate your standard or remove the check all together.

With the Code Query Language, the sky is the limit.  Did I mention the editor comes with Intellisense?

Reports

Go ahead and generate a report.  Check out this example which gives you a run down of the application and assembly metrics, an assembly dependency diagram, CQL Queries and Constraints and much more.  Whereas the VisualNDepend UI is geared toward the architect or lead developer type who is wanting to really dig into an application, the report seems to be more suitable for a less technical audience.  Perhaps the report could be used as part of an executive summary or could complement a developer’s code review.  Simply, it is a professional output (HTML only, I think) consisting of endless information and even pictures. 

Integration

Very quickly I wanted to call out that NDepend integrates not only with VisualStudio and Reflector but also MSBuild, NAnt, and CruiseControl.NET.  I personally think it is great that NDepend was implemented in a manner in which its frequent (read: continuous) and easy (read: automated) use is promoted.  Well done.

Final Thoughts

NDepend is darn impressive. It is a “mind blower” if you will.  NDepend provides more than ample metrics, a flexible (albeit busy) UI, a customizable query language, professional reports and hooks into applications like Visual Studio and Reflector along with support for processes like automated builds and continuous integration.  If you really want to know your code and you are looking for a tool which provides more than simple application metrics, NDepend may be the right product for you.  I highly suggest you check it out.

Getting Started with Inno Setup

For the first time in years, I needed to distribute my application to the end user’s machine via an online download.  To do this effectively and professionally, I, of course, needed an install package.  Over the year, I have used both Wise and InstallShield but they both cost money and I don’t recall them being all that easy to manage.  This was, however, years ago.  More recently I have, like many developers, used Windows Installer to imagegenerate MSIs for very simple (read: file copy) deployments. There’s nothing flexible or particularly pleasing about MSIs, but one can typically get them created with a few button clicks.  For the installation of internal applications, MSIs are more than tolerable, in my opinion.  Other than those options, I was quite ignorant on the subject of installers so I briefly evaluated three free candidates:

  • Windows Installer XML (WiX) Toolset is a Microsoft open source project used to create the Office 2007 installer. WiX includes some advanced capabilities, but it has a steep learning curve even though the scripting language is XML-based.
  • NSIS (Nullsoft Scriptable Install System) is a professional open source system to create Windows installers. It is designed to be as small and flexible as possible and is therefore very suitable for Internet distribution. It has a rich feature list, a good set of online samples and a good community following.
  • Inno Setup is another free, open source installer for Windows programs. First introduced in 1997, Inno Setup today rivals and even surpasses many commercial installers in feature set and stability.

Decision

After a quick review of each product, I opted to run with Inno Setup primarily because it had the ugliest website, all of their product award links are broken and it isn’t known by any acronym…yet.  Joking aside, I chose Jordan Russell’s Inno Setup because it met all of my requirements almost effortlessly.  Here’s the rundown of what I needed:

  • Check for the .NET Framework and install if not found
  • Check if Remote Registry is running and start if stopped.
  • Check is UAC is enabled and provide user dialogue.
  • Open website(s).
  • Create quick launch, desktop, start icons.
  • Read, update registry.
  • Ask custom questions and manage response.
  • Launch applications.
  • Install silently.
  • Create associated uninstaller.
  • Show/acknowledge terms of service.
  • Display readme.
  • Customizable/skinnable display.  
  • Etc

Additionally, Inno Setup it is such an easy tool to use and test and it has been around for a long while and has a great feature list:

  • Support for all versions of Windows in use today: Vista, XP, 2008, 2003, 2000, Me, 98, 95, and NT 4.0. (No service packs are required.)
  • Extensive support for installation of 64-bit applications on the 64-bit editions of Windows. Both the x64 and Itanium architectures are supported. (On the Itanium architecture, Service Pack 1 or later is required on Windows Server 2003 to install in 64-bit mode.)
  • Supports creation of a single EXE to install your program for easy online distribution. Disk spanning is also supported.
  • Standard Windows 2000/XP-style wizard interface.
  • Customizable setup types, e.g. Full, Minimal, Custom.
  • Complete uninstall capabilities.
  • Installation of files:
    Includes integrated support for “deflate”, bzip2, and 7-Zip LZMA file compression. The installer has the ability to compare file version info, replace in-use files, use shared file counting, register DLL/OCX’s and type libraries, and install fonts.
  • Creation of shortcuts anywhere, including in the Start Menu and on the desktop.
  • Creation of registry and .INI entries.
  • Integrated Pascal scripting engine.
  • Support for multilingual installs.
  • Support for passworded and encrypted installs.
  • Silent install and uninstall.
  • Full source code is available (Borland Delphi 2.0-5.0).

Oh, and have I mentioned that it is free? 

Getting Started

The basic installer includes the Inno Setup Compiler, documentation and numerous samples.  If you want to get started quickly just download Inno Setup and review the sample scripts.  You’ll be creating your own installers in no time.  Alternatively, you could download/install the QuickStart Pack, but I honestly do not think it is necessary.image

As I mentioned, a review/compilation of the samples can provide a quick, easy introduction into the impressive tool. All the examples are worth a look, but I feel it is necessary to give a few special mention:

  • Example1.iss, Example2.iss and Example3.iss provide a great foundation as they demonstrate how to access the registry, add a desktop icon, include a readme file, etc, etc, etc.  
  • If you are planning to do anything non-standard, play around with the CodeExample1.iss sample.  It essentially builds a basic setup, captures every installer event, includes custom functions, and demonstrates how to extract/expand files, display dialogues and issue before and after installer actions. 
  • Finally, if you want to build custom pages, check out CodeDlg.iss which demonstrates how to build installer pages with custom questions and user input options.

My suggestion is to review the samples from within the Compiler.  The Compiler doesn’t have intellisense or anything, but it will obviously validate your script and call out where imageinvalid syntax exists.  The Compiler also allows you to immediately “run” your installer script (by clicking on the green arrow button) or compile the script (by clicking on the fourth button from the left.) What the heck is that anyway?  The Compile IDE is a fancy notepad with options and actions.  It’s simple and I dig it.

Speaking of simple, here’s an example script.  You would have to build on its foundation if you wanted to do anything fancy, like read from the registry, but these few lines practically do it all.  They copy three files into the Program Files sub directory, displays a read me file and add an icon to the Start Menu.  And all the standard installer pages (splash, location, completion, etc) comes along for free — free meaning no effort and no code.

[Setup] AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
DefaultGroupName=My Program
UninstallDisplayIcon={app}\MyProg.exe
Compression=lzma
SolidCompression=yes
OutputDir=userdocs:Inno Setup Examples Output

[Files] Source: “MyProg.exe”; DestDir: “{app}”
Source: “MyProg.chm”; DestDir: “{app}”
Source: “Readme.txt”; DestDir: “{app}”; Flags: isreadme

[Icons] Name: “{group}\My Program”; Filename: “{app}\MyProg.exe”

Extra Help

Finding the right syntax wasn’t always a breeze as everything isn’t covered in the samples.  With that said, the best online reference I found was an Inno Setup Manual hosted at AgentSoft.com. I can’t say I know the connection between AgentSoft and Inno but I’m still very happy to have found the reference.  I also found various “real world” installer scripts, like this one, posted online which really helped facilitate my ramp up.

.NET Framework Install Script

In my requirements list, I called out the need to check for the .NET Framework and install if it wasn’t found.  This functionality is a snap using Inno Setup — just be sure to use the Client Profile version of the installer.

[Files] Source: “Executables\dotnetfx35setup.exe”; DestDir: “{tmp}”; Flags: deleteafterinstall

[Run] Filename: {tmp}\dotnetfx35setup.exe; Parameters: “/Q /NORESTART”; Check: Is35FrameworkInstalled; Flags: runhidden shellexec waituntilterminated; StatusMsg: “This may forever.”

[Code] function Is35FrameworkInstalled():Boolean;
begin
    Result := not RegKeyExists(HKEY_LOCAL_MACHINE, ‘SOFTWARE\Microsoft\Net Framework Setup\NDP\v3.5’);
end;

Summary

I’ll keep it short and sweet: Inno Setup is one slick piece of software that made the dreaded task of creating a custom installer one heck of a lot easier than it could have been.  I’ve added Inno Setup to my toolbox and I highly suggest you do too.