One of the key aspects of software engineering is the ability to investigate with curiousity the shape and space of the problem, to understand it's parts, and be able to assemble them into something useful and valuable.

This applies not only to the actual software, but to the entire system of conception, invention, implementation, deployment, and maintenance. It looks at not only how is this particular feature going to be broken down into objects, functions, procedures, or what-have-you, but how are those parts going to be verified, validated, and assembled, but how the people that are working on these
various parts and assemblies going to work together.

So one fundamental of Software Engineering is:

Being able to see the whole as well as the parts, how they
come apart and fit back together.

One needs to learn how to do this, of course, as most people aren't born with this ability. Some people acquire it earlier than others, some may never acquire it, but it is something which can be taught and learned.

But how?

Civil Engineering is arguably the first type of engineering humans developed. Learning to make bridges that spanned rivers, chasms, and generally eased commerce has been a part of human civilization for millennia.

But how did it start? Primarily, because bridges fell down. Tossing a couple of logs across the stream eventually was good enough, but if you wanted something to last longer than the next flood, you needed to figure out ways to keep such things from washing away or falling down and
killing people in the process.

So the early engineers learned to study failure, and learn why the things we construct break and fall apart. A software engineer must do the same thing in order to understand how to build better
software. It's not quite enough to *just* study failure, of course; one also needs to understand successful projects.

In this, we study best when we study together, which is one reason the Open Source movement has been a real benefit to learning software engineering. Even in proprietary development, though, sharing code with colleagues through peer reviews, pairing, and study is very

So another fundamental of Software Engineering is:

A deep sense of curiosity about the internals of software and
project that work and that fail, and understanding what makes
something good and what will cause future problems.

I mentioned the notion of "Laws", or Fundamental Concepts of Software

I'll just list some of them off, there's more than adequate information about these out there, and different people have their favourites.

  1. Don't Repeat Yourself
  2. Principle of Least Astonishment
  3. Principle of Least Knowledge
  4. Make it work, then make it pretty, then make it fast.
  5. Understand principles about what makes a good software

Shifting a bit, I'm now going to talk more technically and pragmatically, and these will be a bit more directed.

  1. Don't learn a syntax, learn a language or framwork's idioms, practices, the problem spaces it works best in, those it doesn't
  2. Don't learn a single language or framework. In Pragmatic Programmer, they urge you to learn a new language every year. The thing is don't just learn a language of the same kind, learn one that has different ways to solve problems. If you're using an imperative language such as C, learn Lisp or Smalltalk. If you primarily script in Perl, learn Ruby and Python. Learning is never wasted.
  3. Work both with exercises (kata) and with real problems. There is nothing really more satisfying than solving one of your own problems, and these are the ideal vehicles to apply learning to.
  4. If you encounter some piece of a project that you don't know how to implement, or an area that you need more skill in, break out into a small example and practice that until you understand it.

Another principle of Software Engineering is:

Be constantly practicing and learning your craft.