I grit my teeth when I read that software engineering is not engineering because we don't suffer from any constraints. This Is Wrong, and off the top of my head, here are some reasons why:
Where a builder uses wood, metal, sheetrock, etc. as their basic materials, we software engineers use algorithms both formally and informally specified. At its simplest, an algorithm is the set of instructions you give to the computer to accomplish some task. Basic algorithms (Quicksort, hash tables, and so on) are the software engineer's basic materials. Although it appears not to have been often thought of this way, each program/module/etc. is the implementation of an algorithm for solving that task, so we deal with large, complex (and often not well specified) algorithms all the time. I think of Quicksort et.al. as the wood, metal, etc., while larger algorithms (HTTP server, etc.) serve as the sills, soffits, bay windows, and so on.
We do not live in a world of 0 cycle times and infinite memory (or disk). Each algorithm has different time/space requirements. A Perl array or linked list may be quite suitable for searching small lists of items, while a hash will likely be good for medium-sized lists, with (in Perl) a hash backed by a database might be needed for searching all medical entries in the U.S. Yellow Pages. Builders don't use 2x4s as the main structural elements in skyscrapers, nor do we software engineers use an in-memory hash to store all 3m-resolution images of the U.S.
As software engineers, we struggle with the complexity of our designs all the time. It still amazes me how many general-purpose editors do not support regex search&replace with grouping (s/Jim said/$1 said/), more than 20 years since that feature first appeared (IIRC). Regexes, closures, rule-based systems, et.al. hide complexity so that (for the most part) we can concentrate on the design rather than implementation details. For example, languages such as Perl with integrated regexes make it easy to use regexes to solve otherwise complicated problems (as someone whose first 2 languages were FORTRAN IV and assembly, I cannot tell you how glad I am for Perl regexes and their kin). I have personally written 3 hash implementations to help me overcome implementation complexity (the last recently as the late 90's for a 15-year-old C system). Progress towards higher-level code constructs has made the jobs of all of us software engineers easier (come on, who these days would like to create something like Amazon in FORTRAN IV or circa-1980 Pascal? and without today's libraries and frameworks)
In any system, the most complex subsystems are the ones with people embedded in them. Writing an OS kernel or a natural language subset interpreter is child's play compared to the complexities of dealing with multiple customers for the same product with conflicting requirements and this does not cover the common case, where people know that they would like a computer system to help them solve their problem, but they cannot specify to you or how the computer system should accomplish that goal (they know the problem domain, but not the solution domain (and they may not even have had time to reason about their problem domain)).