Abstractions are a beautiful thing, and it is said that any problem in technology can be solved with another level of abstraction or indirection. Tremendous. But like with most things, there is a flip side.
Once upon a time you would program by hardwiring hardware. This evolved to general purpose hardware and machine code. Higher level abstractions came along with assembler; then C with compilers and so on and so forth. Now we regularly use things like Visual Studio, the Dynamic Language Runtime and Iron Python. Other technologies take the same trajectory. One moment you are writing angle brackets onto a HTTP stream to do SOAP and then next you are adding a service reference to your C# project and you never see an angle bracket ever again because even the XML configuration file has a GUI editor!
All the abstractions are clearly a great thing but the flip side is when things go wrong. If you are relying on SQL Server, for example, and you are not seeing the performance you expect you might employ some basic knowledge of the abstraction by profiling and having SQL suggest indexes. What next? Peel away some of the abstraction. Maybe you need to know about query plans and statistics or files and filegroups and disk configurations. This is what specialists are for. Subject Matter Experts. People who invest in knowing the abstractions and a significant number of layers beneath.
However, there are fundamentals, and whatever the abstractions are we should know these fundamentals (even if some of those are abstractions in their own right!). Each domain will have different fundamentals. What would you choose as your fundamentals? TCPIP, DNS, SMB? XSD, XML, WSDL, SOAP, WSI? HTTP, FTP? Two phase commit? Distinguish between throughput and latency, processes and threads? The list actually gets pretty big. Some fundamentals are just engineering concepts: parallel versus serial or centralised versus distributed etc.
Why am I writing this post? With the explosion of technologies, frameworks and versions it would seem a lot of people are having to trade a knowledge of fundamentals for a vast but cursory knowledge of very high level abstractions and I feel it is hurting. Is it a sign of my age? Is it just that today's abstraction are tomorrow's fundamentals? After all, if I think my vague understanding IL is clever, it is still not machine code, fetch execute cycles and binary (I can't even remember what two's compliment is!) but you have to draw your own boundary at some point!
Fundamentals allow you to decompose your solution and see it for what it really is. It won't matter how many shiny bits it has, it is just the composition of fundamentals. For example, you'll be able to use reflector and see that the code is a single threaded foreach loop making cross machine calls. There is no magic in that - the solution is clear.
I am feeling it more and more lately that great teams are a combination of the generalist and the specialist. They both know their fundamentals and engineering concepts - this can never be lost, but one invests in knowing a very broad range of abstractions and one delves deep. But either way both should recognise what fundamentals are relevant to their domain and keep investing in them too.
I think one of the hardest abstractions I have ever worked with was VB and MTS. It was very productive to crank out COM components in VB. But when things started to go a bit wrong, you were so far from the next level of abstraction you were in a world of pain! Remind me: what is a Single\Multi Threaded Apartment? What is Activation? What is Thread Local Storage and Thread Affinity? I didn't know I just wanted to write my VB!