John Kaster

Behind the Screen

Delphi Cookbook review

leave a comment »

Review of the book Delphi Cookbook by Daniele Teti.

Before proceeding with my review, you may want to read this other review by Simon J Stuart which provides a good overview of what you can find in the book. I also received a review copy from the publisher, and I’m glad I requested one!

Overall impression

The book uses a great pattern, where a topic is introduced, code is shown to demonstrate it, explanations and observations about the technique are discussed, and suggestions for additional usage or other resources are provided. This “explore more” section of the book may actually be its most valuable part, because Daniele provides specific links that point to good resources to use for each of the recipes covered.

The code examples are useful and as concise as is reasonable.

The order of the book is logical and does a good job of building on some of the previous recipes in later parts of the book:

  1. Delphi Basics
  2. Become a Delphi Language Ninja
  3. Going Cross-Platform with FireMonkey
  4. The Thousand Faces of Multithreading
  5. Putting Delphi on the Server
  6. Riding the Mobile Revolution with FireMonkey
  7. Using Specific (mobile) Platform Features

This is a valuable book to keep handy for when you may need to implement any of the techniques it covers. In short, it is exactly what a “cookbook” should be, with quick and reliable recipes to help you create a good solution for a technical issue.

Some specifics

For example, there’s a great, short exploration for taking advantage of generics. Hidden in one of the discussed “higher order” functions for generics (map, reduce/fold, filter) is something that deserves to be called out briefly in the book (although it is not).

class function HigherOrder.Filter(InputArray: TArray;
    FilterFunction: TFunc): TArray;
var
  I: Integer;
  List: TList;
begin
  List := TList.Create;
  try
    for I := 0 to length(InputArray) - 1 do
      if FilterFunction(InputArray[I]) then
        List.Add(InputArray[I]);
    Result := List.ToArray;
  finally
    List.Free;
  end;
end;

 

This small sample shows one of the cleaner methods of populating a dynamic array result that can subsequently be lifetime managed by the runtime.  The TList object is efficient for growing one item at a time. A dynamic array is not. Often, the result for the dynamic array is preallocated to some high bound (in the sample above, it would be the length of the input array), then resized before the return to shrink the array back down to the number of elements matching the filter. By using TList<T>, then freeing it, the array size is only manipulated once and the List.ToArray call makes the code clean and sustainable.

Mobile development with Firemonkey

The book has many detailed and useful examples for mobile development with FireMonkey. This is the section of the book where I learned the most, because I haven’t worked on mobile apps with Delphi. There are many useful tidbits covered in this section that are important for mobile development: using mobile databases, implementing server and client-side functionality, camera and phone manipulation, application lifecycle awareness, and more.

Platform-specific features

The platform-specific features chapter goes beyond mobile FireMonkey recipes to making calls from Delphi to iOS and Android SDK calls, and is an excellent way to wrap up the book.

Other recipes I’d like to see

Some things I think would be good to have in the book are:

  • In the UI section:
    • effective use of actions
    • effective use of frames
    • input value validations (form validation)
  • in the section on streaming, it would be handy to explore reliable determination of the encoding used by a file.
  • for threading, effective use of the new XE7 Parallels library
  • for Delphi on the server,
    • how to secure your web application (including using secure CDN resources for jQuery, etc)
    • using dynamic arrays and records for JSON to avoid all the “free” calls for TObjectList<T> (this works very well with SuperObject, for example)

A minor nit

I don’t understand what Daniele means by “bounce” as in: “I see too many business applications that are composed by a bounce of dialog windows.”

Conclusion

Daniele did a great job on this book, and I hope he continues to update it with new recipes in the future.


			

Written by John Kaster

November 26, 2014 at 8:31 am

Posted in Delphi

Working for the weekend

with 4 comments

At Transactis, one of the utility methods I’d been meaning to develop was the calculation of weekend days (Saturday and Sunday) between two dates. I wanted something that was LINQ-able for the collection of dates in the range. After an entertaining Skype chat with Tim Jarvis, a friend of mine who does not work at Transactis, but is a certifiable LINQ nut, this was the end result, which is contained in the Utility class UT.cs:

        public static IEnumerable<DateTime> GetWeekends(int year)
        {
            DateTime fromDate = new DateTime(year, 1, 1);
            DateTime toDate = new DateTime(year, 12, 31);
            return GetWeekends(fromDate, toDate);
        }

        public static IEnumerable<DateTime> GetWeekends(DateTime fromDate, DateTime toDate)
        {
            if (fromDate.DayOfWeek == DayOfWeek.Sunday)
            {
                yield return fromDate; // Add end of weekend to this result
                fromDate = GetNextDateForDay(fromDate, DayOfWeek.Saturday);
            }
            else if (fromDate.DayOfWeek != DayOfWeek.Saturday)
                fromDate = GetNextDateForDay(fromDate, DayOfWeek.Saturday);
            TimeSpan ts = toDate - fromDate; // Days from current weekend date to EOY
            int daysToAdd = ts.Days;
            for (int i = 0; i <= daysToAdd; i += 7)
            {
                yield return fromDate.AddDays(i);
                if (i+1 < daysToAdd)
                    yield return fromDate.AddDays(i + 1);
            }
        }

 

(This code uses GetNextDateForDay() from the excellent blog post http://angstrey.com/index.php/2009/04/25/finding-the-next-date-for-day-of-week/.)

The typical usage scenario for us is assigning all weekend days for a given year. This led to the following int extension method:

    public static class IntUtil
    {
        public static IEnumerable<DateTime> GetWeekends(this int year)
        {
            return UT.GetWeekends(year);
        }
    }

 

With this int overload, it’s now a trivial matter to get an enumeration of all weekend days for any year:

var lastYear = 2010.GetWeekends();
var thisYear = 2011.GetWeekends();
var nextYear = 2011.GetWeekends();

 

I hope you find this technique useful for something you need. One obvious one would be getting a specific day of the week for a given date range, not just Saturday and Sunday. This routine is specifically optimized to return that pair of dates.

 

P.S. Thanks to Scott, he-who-is-not-a-fool who answered my tweet question about a good source code plug-in for Windows Live Writer on WordPress.com hosted blogs. You can get his plug-in from his website.

Written by John Kaster

May 25, 2011 at 6:35 am

Posted in c#, LINQ

A bug fix for System.Linq.Dynamic and a solution for the Entity Framework 4 .Skip() problem

with one comment

My team is converting one of our applications to Entity Framework 4 from an older data binding architecture where much of the data binding code was handwritten (many years ago in .NET land).  Some of the application code uses properties that have a different case than the underlying property in the newly-generated Entity Framework code based on the existing database metadata.

C# is so sensitive

Since C# is a case sensitive language, of course this matters a bit.

However, it didn’t really become an issue until I had to do this for one of our entity objects for application code compatibility:

 
    public partial class Foo
    {
        /// <summary>
        /// Alias for id
        /// </summary>
        public int ID
        {
            get { return this.id; }
            set { this.id = value; }
        }
    }

 

Yes, boys and girls, the primary key field in the database is named “id”, but the application code refers to the property as “ID.” This usually isn’t that big a deal, because you can just alias like shown above, and the client code is happy.

L2E doesn’t understand your C# extensions

There is one situation where this will end up being a problem though – if you happen to use “ID” instead of “id” in a LINQ to Entities (L2E) query. You’ll get that dreaded message about the specified type not being supported in L2E, because it can’t translate your custom C# property extension into SQL. Read the blog post above or search for the

The specified type member is not supported in LINQ

for further discussions.

Usually, you can just ensure your LINQ query uses the “native” property rather than the extension. However, there was one scenario where it wasn’t convenient for me to explicitly specify “id” rather than “ID”, because of another problem I needed to solve.

L2E .Skip() requires .OrderBy() first

If you try to call .Skip() (and .Take()) to get a partial result set back from a collection in L2E, you need to call .OrderBy() first. If you don’t, you’ll see this run-time error:

The method ‘Skip’ is only supported for sorted input in LINQ to Entities. The method ‘OrderBy’ must be called before the method ‘Skip’.

(You can search for that error message as well and get tons of hits.)

Because of this requirement, I needed to find a way to generically support skip and take without having to explicitly specify a sort order for every collection in our data model. I hit upon what I think is the most elegant solution: sorting on the primary key for the collection when no explicit sort order was defined.

The generic .OrderBy() solution

For utility classes in our framework, I copiously document to increase awareness and understanding of the solutions we customize, so I’ll just paste the code here. (I found GetPrimaryKeyInfo() on Stone Lasley’s blog, so thanks for that, Stone!):

/// <summary>
/// Calculate the starting page position for the paged selection
/// </summary>
/// <param name="pageSize">Number of items to return per page</param>
/// <param name="pageIndex">Index of current page, starting with 0 as the first page</param>
/// <returns>The "skip" offset for the first row of the requested page</returns>
public static int PageStart(int pageSize, int pageIndex)
{
     return pageIndex * pageSize;
}

/// <summary>
/// Retrieve the primary key for the passed <c>EntityObject</c> descendant
/// </summary>
/// <typeparam name="T">Strongly-typed <c>EntityObject</c></typeparam>
/// <returns>The property info for the primary key of the <c>EntityObject</c></returns>
public static PropertyInfo GetPrimaryKeyInfo<T>()
{
     PropertyInfo[] properties = typeof(T).GetProperties();
     foreach (PropertyInfo pI in properties)
     {
         System.Object[] attributes = pI.GetCustomAttributes(true);
         foreach (object attribute in attributes)
         {
             if (attribute is EdmScalarPropertyAttribute)
             {
                 if ((attribute as EdmScalarPropertyAttribute).EntityKeyProperty)
                     return pI;
             }
             else if (attribute is ColumnAttribute)
             {
                 if ((attribute as ColumnAttribute).IsPrimaryKey)
                     return pI;
             }
         }
     }
     return null;
}

/// <summary>
/// Sorts and extracts the selected "page" from the collection
/// </summary>
/// <typeparam name="T">Type of collection</typeparam>
/// <param name="collection">collection to sort and extract</param>
/// <param name="pageSize">number of rows per page</param>
/// <param name="pageIndex">0-based index for the page</param>
/// <param name="totalRecords">reference <c>int</c> to return total number of rows 
/// </param>
/// <param name="sortExpression">Optional. Name of column(s) on which to sort. Defaults to EntityKey name if not set.</param>
/// <param name="sortDirection">Optional. Sorting direction, either (case insensitive) 
/// "asc", "ascending", "desc", or "descending"</param>
/// <param name="defaultKey">Optional. If the primary key cannot be determined from the T type passed in, 
/// this value will be used for the sort expression.</param>
/// <remarks>Requires System.Linq.Dynamic.
/// L2E 4.1 will also generate the error:
/// The method 'Skip' is only supported for sorted input in LINQ to Entities. The method 'OrderBy' must be called before the method 'Skip'.
/// if .OrderBy() is not called before .Skip(), so it's good that SortExpression&lt;T&gt;() provides the default entity key to
/// sort on if no value is provided for <c>sortExpression</c>
/// </remarks>
/// <returns>The sorted and extracted list</returns>
public static List<T> PagedResults<T>(IQueryable<T> collection, int pageSize, int pageIndex, ref int totalRecords,
     string sortExpression = null, string sortDirection = null, string defaultKey = null)
{
     string sort = SortExpression<T>(sortExpression, sortDirection, defaultKey);
     int start = PageStart(pageSize, pageIndex);
     List<T> list = collection
             .OrderBy(sort)
             .Skip(start)
             .Take(pageSize)
             .ToList();

     totalRecords = collection.Count();
     return list;
}

/// <summary>
/// Create the sort expression for the entity
/// </summary>
/// <typeparam name="T">Entity type on which to sort</typeparam>
/// <param name="sortExpression">Expression on which to sort. Empty or null defaults to entity key.</param>
/// <param name="sortDirection">Either null, blank, ASC, or DESC</param>
/// <param name="defaultKey">Optional value to use as the default sort key. 
/// Only used if sortExpression is empty or null, not required if the object type used 
/// is an entity with a primary key property.</param>
/// <returns>The (hopefully) valid sort expression</returns>
public static string SortExpression<T>(string sortExpression, string sortDirection, string defaultKey = null)
{
     if (string.IsNullOrEmpty(sortExpression))
     {
         if (string.IsNullOrEmpty(defaultKey))
         {
             // Default the sort expression to the primary key
             var key = GetPrimaryKeyInfo<T>();
             sortExpression = key.Name;
         }
         else
             sortExpression = defaultKey;
     }
     return string.Format("it.{0} {1}", sortExpression, sortDirection);
   }
}


 

With those routines, you can:

  • Automatically determine the column name of the primary key for an entity
  • Create a general-purpose sort call
  • Retrieve a paged result set for any L2E collection

In PagedResults<T>(), you may want to return IQueryable<T> rather than List<T> but for our purposes we also wanted to get the total records for the requested page, so we needed to enumerate the collection to get an accurate count.

So, with these handy dandy utility methods we were off to the races … almost.

Remember that id to ID alias shown at the top of this post? This generic default sorting solution uncovered an issue with System.Linq.Dynamic (which I think is awesome, by the way).

System.Linq.Dynamic must respect casing

At run-time on my requests to retrieve a page of the “Foo” collection, I was getting “.Skip() needs .OrderBy()” error we’ve already covered, because Dynamic LINQ was returning “ID” in the parser that converts the string to a valid OrderBy lambda expression.

So, after a reasonably painless late-night (tonight!) debugging session, I found the issue in FindPropertyOrField().

I think I have the latest version of Dynamic.cs. (The “blessed” version isn’t easy to find/verify in web searches.) In my version of the file, FindPropertyOrField() begins at line 1330. Shown below are my changes, with “// jfk …” comments after the lines I’ve modified or added. These simple tweaks got me unblocked from my problem, and I am now happily paging through any of my L2E collections again.

MemberInfo FindPropertyOrField(Type type, string memberName, bool staticAccess) {
    MemberInfo result = null; // jfk added variable for return result
    BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly |
        (staticAccess ? BindingFlags.Static : BindingFlags.Instance);
    foreach (Type t in SelfAndBaseTypes(type)) {
        MemberInfo[] members = t.FindMembers(MemberTypes.Property | MemberTypes.Field,
            flags, Type.FilterNameIgnoreCase, memberName);
        if (members.Length > 1) // jfk Check to see if we have more than one match
            result = members.SingleOrDefault(m => m.Name == memberName);  // jfk Look for exact case match
        if (result == null && members.Length > 0) // jfk
            result = members[0]; // jfk default to the first match. Good as any!
    }
    return result; // jfk
}

 

Can someone please make sure the appropriate person at Microsoft gets this fix, and updates Dynamic.CS for everyone?

It would be good to implement something like the generic .Skip() solution I use, too.

Thanks in advance!

I hope you find the code useful.

By the way, Transactis is looking for excellent software developers. If you’re interested in working in Dallas, Texas, feel free to contact me.

Written by John Kaster

May 19, 2011 at 4:07 pm

Posted in LINQ

MacBook Pro Impressions #3

with 3 comments

In my first and second posts on this subject, it looks like the MacBook has been losing in the comparison to Windows 7, so I thought I’d do a quick (we’ll see!) post on some things I do like about the Mac.

Spotlight rocks

Spotlight kicks butt all over Windows search, particularly when searching in the windows start menu, which frequently doesn’t even find installed software by name. Spotlight is fast, it finds everything, and the UI is set up so you can just type as much as you need to find the item you want, you hit enter, and it opens. I actually almost never use my dock.

I started using it even more after I discovered the Command+Space hotkey that invokes the spotlight search.

Fancy fingerwork

The 4-finger swipes are quite handy (pun intended) now that David Clegg has told me about them.

  • Swipe 4 fingers left or right: show all running tasks
  • Swipe 4 fingers up: show your desk top
  • Swipe 4 fingers down: show all open windows
  • Swipe 4 fingers in the opposite direction: revert your view

3-finger swipes that work in Safari and Firefox (at least):

  • Swipe 3 fingers left: move backward to previous browser page
  • Swipe 3 fingers right: move forward to next browser page

Lots of configuration options

As several people pointed out in comments to my last post on this subject, there’s also a lot of configuration options available on the mac. It turns out I disagree with Apple on what should be the default setting for at least a few of them Winking smile.

The following bookmark is one I refer to when I remember to teach myself some more Mac features, also.

http://apple.stackexchange.com/questions/400/mac-os-x-hidden-features-and-nice-tips-tricks

Written by John Kaster

April 14, 2011 at 8:18 am

Posted in IT Industry, Mac

Fun and games with MSSQL installations

with one comment

After spending a couple minutes scratching my head wondering where my SQL Profiler was for SQL 2008 Standard R2, I did some searching and found out that Microsoft evidently thinks you don’t want a SQL Profiler on a machine that has Visual Studio on it.

The Visual Studio installation also installs SQL Express. There’s lots of samples that are pre-configured to use SQL Express. That’s fine with me.

The headaches come when you want to install SQL Standard or higher on a machine that already has SQL Express installed. The profiler is part of the “Complete” management tools, as explained in this blog post.

Problem is, I couldn’t select “Complete” when I installed SQL Standard, because I already had SQL Express on the machine.

You can’t get there from here

A picture’s worth a thousand bug reports, hopefully. Here’s my confounded picture.

image

What’s the solution? Evidently, it’s wiping out all vestiges of “SQL Server” from my machine in add/remove programs and starting all over. Again. (I’d already had to do this once because SQL 2008 R2 had issues with installing on a different version of SQL server, and SQL 2008 (not R2) can’t install on Windows 7.)

Please, Microsoft – think for a couple seconds about your installation practices for future MS SQL installer releases, and make some appropriate implementation decisions. Thanks.

Written by John Kaster

April 8, 2011 at 9:43 am

Posted in IT Industry, SQL Server

MacBook Pro Impressions #2

with 9 comments

Wow, I’ve been so busy since my last post on my MacBook impressions, I’m going to keep this post to some quick observations so I don’t fall so far behind I never get back to this topic.

UI Oddities

I keep hearing about how great the Mac UI is, and how much better it is than Windows. Maybe it’s because I’m comparing it to Windows 7, but I’m just not feeling the “Mac UI” love that much. I really don’t see that it’s significantly better than Windows. Some examples:

  • Hitting “enter” on a file in Finder (Mac’s version of windows file explorer) allows you to rename the file. It doesn’t open the file.  Having the Enter key invoke a file rename UI rather than opening the file I’ve “selected” really doesn’t seem like the best choice.
  • I can only resize a window by clicking on the bottom-right corner of the window. I can grab any edge in Windows and resize the window. Windows is definitely more user friendly for this, and minimizes mouse movements.
  • Apps that have multiple windows frequently hide my most recent window when I have to temporarily switch tasks, and the only way to see them is to hold down icon in the Dock (taskbar) and wait until the windows are gathered, then I have to click on the hidden window to bring it back up.
  • When I stick a movie DVD in the drive, the Mac doesn’t do anything. I have to start the DVD player explicitly. I don’t know what the reasoning behind this, but sticking a DVD in the DVD drive is a User Interface event, and it should respond to that event. Windows certainly does.
  • The Mac has drag and drop issues for several stock Mac applications when trying to drag a file from a networked drive into the application. In several instances, it just won’t work at all. I have to use that same Finder window that’s pointing to the networked drive, copy the files locally, then use the files from the local copy. Lame.

Quality comparison

For those people who claim that the Mac doesn’t crash, spin up on CPU cycles, or lockup as much as Windows does, all I can say is, you’re wrong. I’ve actually experienced more frequent “issues” with my MacBook than with my old Windows laptop that was not built for Windows 7 but was upgraded to Windows 7 Ultimate.

I have also had very flaky external display issues with my Dell U3011. Calls to Apple support didn’t resolve it, other than insisting it was my Dell display that was causing the problem. After more than a month of problems, and finally not being able to connect to my external display at all, I decided to give the “Genius Bar” at my closest Apple store a try (an hour round-trip away from the house.)

After plugging in the laptop to the monitor (also lugged up to the Apple store) at the Genius Bar, it “just worked.” So something related to the amount of time disconnected/powered down reset the display issue. Everything I know about hardware and software issues points to it being a display driver problem, though.

I have since learned to never close the lid (putting it to sleep) on my MacBook when connected to my external display. Whenever I’m going to close the lid, I disconnect the mini-DisplayPort to DisplayPort adapter first. I have had zero display issues since adopting this practice.

Bad design decision

I spent about a month trying to figure out why my line-in/microphone input wouldn’t work on my Macbook when doing voice conferencing. I even talked to two Apple Care technician about it, and they didn’t know. The people at the Genius Bar finally gave me a partly accurate answer – rather than using a standard Laptop headset that works on any one of dozens of different kinds of devices, I have to have a “USB headset”. What they really meant is I need a powered microphone attached to the input jack.

Requiring a powered mic for a laptop or any other portable device is a ridiculous design choice/limitation. There is absolutely no valid reason to require a powered microphone as an input source for a laptop computer.

More observations when I have time. There’s plenty more to bring up. I need to start taking better notes while I’m working …

Written by John Kaster

March 15, 2011 at 8:10 am

Posted in IT Industry, Mac

Software Engineering Job Openings at Transactis

with one comment

I posted the announcement that we’re hiring previously on my blog, but I heard from some people they wanted more details on the positions to be filled, so here it is.

At Transactis, we are looking for enthusiastic software developers who are constantly improving their coding skills, efficiency and technical knowledge, and who love to write and reuse beautiful, high-quality code. Our software is critical for our line of business, so it must be high quality and high performance.

We have immediate openings for software engineers at our Dallas/Fort Worth Texas office. We have a small development team and plan to keep it that way, so the opportunities for personal growth, fresh challenges, and better approaches abound. Transactis offers competitive salaries, bonuses, and a complete benefits program. Furthermore, our software engineers work with the best tools money can buy.

Responsibilities for software engineering positions include: developing new application software, framework and business components ; learning and using new techniques, technologies, and tools; writing unit tests and test suites; designing and developing new product features; and maintenance, bug fixing, and performance improvement of existing software.

If you’re someone others go to for advice on the best way to solve a technical problem, or the person who shares the latest best practices with your colleagues, or can’t wait to tell your friends or significant other about the latest cool thing you wrote even when they won’t really understand it, you could be a good candidate for this position.

A qualified candidate must:

  • Be eligible to work in the United States
  • Be able to relocate, or already live in the Dallas/Fort Worth, Texas area
  • Be very motivated to resolve product issues quickly and reliably
  • Have excellent oral and written communication skills
  • Enjoy being a member of a software development team
  • Thrive on technical challenges and take pride in finding elegant, sustainable solutions
  • Constantly be thinking of ways to improve our productivity, reliability, and code base
  • Have at least 4 years experience developing with the Microsoft .NET framework, ASP.NET Webforms and/or ASP.NET MVC
  • Be familiar with OOD principles and Test-Driven Development
  • Enjoy writing and using unit tests to validate development releases
  • Have at least 4 year’s experience building C# components
  • Have at least 3 year’s experience developing with LINQ, and an ORM/OPF solution such as Entity Framework, NHibernate, XPO, or OpenAccess
  • Have at least 3 year’s experience with Microsoft SQL Server or scalable database design
  • Have at least 3 year’s experience with WCF, SOAP, and/or REST services development
  • Have a thorough knowledge of agile methodologies
  • Have at least 1 year’s development experience with a Javascript library such as jQuery, Prototype, or ExtJS
  • As an added bonus, have familiarity with financial services such as electronic remittance and bill payment
  • As an added bonus, have familiarity with Delphi
  • Rather flip burgers than code in Visual Basic

I have also posted this job announcement to Careers on Stack Exchange.

Update: a more informative version of the ad is now available on LinkedIn, CareerBuilder, and Dice, too.

Written by John Kaster

January 22, 2011 at 2:58 pm

Posted in Uncategorized

What’s your giving IQ?

leave a comment »

My company, Transactis, just launched a new service called GivingIQ. It’s a great way for non-profits to raise money. I’m going to tell the director of SPIN, my favorite local non-profit, about it so they can get signed up for it. Be sure to spread the word to your favorite non-profits!

Written by John Kaster

January 19, 2011 at 6:16 am

Posted in Uncategorized

What’s the staying power of your code?

with 2 comments

I just reconnected with an old friend (he called us both dinosaurs, but we’re not that old!) on LinkedIn. Brian has been in business so long his company actually has a three-letter domain name, cus.com. CUS Business Systems does auction software and consulting, and many years ago I wrote some utility functions for him.

Part of his reconnection email to me said “We’re still writing software for auctioneers, and still using those rtf routines you wrote for me 20 +/- years ago…”

Naturally, I was amazed and impressed by the “staying power” of code I wrote more than 20 years ago, still being used in production. (This is for a Clipper application, by the way.)

So, this prompted me to ask both of my readers:

  • What’s the oldest code you have that’s still in production use?
  • What language is it written in?
  • What is it used for?

Written by John Kaster

January 19, 2011 at 5:35 am

Posted in IT Industry, Personal

MacBook Pro Impressions #1

with 8 comments

I got a MacBook Pro on December 23rd, 2010.  I’m jotting down my impressions as someone very familiar with DOS and Windows, and not at all familiar with the Mac.

I haven’t worked on a Mac since about 1986, so any previous experience I’ve had with them is irrelevant.

I’m not comparing Windows vs. Mac OSX. In fact, the primary reason I got this laptop is so I could run both Windows and Mac software on the same machine, which I’m already doing.

Naturally, the shipping box for the Mac is attractive and well-designed, with a plain outer cardboard box, and a cardboard anchor/pad for each corner of the inner decorated box. The inner box has a black plastic handle so you can lift the box out of the outer box without any difficulty. I like that the self-contained and compact design of the shipping system.

The lid opens and closes nicely. I think it’s held shut magnetically. The power plug also is magnetic – it plugs itself into the laptop when you get the adapter near the receptacle on the laptop. It’s also reversible, so the cord will run alongside the laptop coming toward the front or the back, allowing you to choose which way works better for your current layout. The power brick has a short plug adapter that can be swapped with a longer cord if you need to reach further to your power source. (I just leave the longer cord on all the time).

Apple provides some introductory training videos I found somewhat useful. It’s interesting that options for also running Microsoft Windows on your Mac are also prominently featured.

The keyboard has a pretty good feel. There’s no home or end key, or page up or page down. The delete key is really a backspace key. I really miss not having both. You have to use various multiple keys to get the missing keystrokes and some of them are less intuitive than others. The use of the command and control keys is completely inconsistent, and is still a source of frustration for a keyboard jockey like me.

I’ll record additional impressions in later posts regarding sleep mode, headphone jacks, ISO support,  “intuitiveness”, spotlight, VMWare fusion/parallels, VPN client, Finder views (no tree!), VoiceOver and more. If you care! Winking smile

Written by John Kaster

January 19, 2011 at 5:24 am

Posted in IT Industry, Mac