Wednesday, January 21, 2015
Fluidity and complexity of programming languages
Almost all languages are fluid; their syntax changes. Some languages (COBOL, C++, Forth) change slowly. Other languages (Visual Basic, Java, C#) change more frequently.
Some languages are simple: C, Python, and Pascal come to mind. Others are complicated: COBOL, C++, and Ada are examples.
* * * * *
It strikes me that the languages with simple syntax are the languages with a single person leading the effort. Languages that were designed (and maintained) by an individual (or perhaps a pair of closely working individuals) tend to be simple. Python is lead by Guido van Rossum. Pascal was designed by Niklaus Wirth. C was designed by Kernighan and Ritchie. Eiffel was created by Bertrand Meyer.
In contrast, languages with complex syntax tend to be designed by committee. COBOL and Ada were designed by committee (for the federal government, no less!). C++, while a descendant of C, has a very complex syntax. While Bjarne Stroustrup did much of the work, the C++ standard committee had a lot of say in the final specification.
The one example of a complex language not designed by committee is Perl, which shows that this is a tendency, not an absolute.
* * * * *
It also strikes me that the languages which change are the proprietary languages developed and maintained by commercial companies. Languages such as Visual Basic, Java, and C# have changed rapidly over their lifetimes.
Languages developed by individuals do change, but slowly, and often by entities other than the original developers. BASIC (another simple language developed by Kemeny and Kurtz) was simple and later enhanced (made complex) by Microsoft. Pascal was simple and enhanced by Borland for their Turbo Pascal product. When Niklaus Wirth wanted to make changes to Pascal, he created the language Modula-2 (and later, Modula-3).
Programming languages designed by committee with strong standards (COBOL, Ada) tend to change slowly, due to the nature of committees.
* * * * *
Languages built within commercial entities need not be complex. They may start simple and grow into something complicated. Java and C# were both developed by individuals, and that initial simplicity shows through their current (more complex) design.
* * * * *
What can we expect in the future? I see little activity (or call for) committees to design languages. This is possibly a long-term risk, as committee-built languages, once adopted as standards, tend to be durable, stable, and cross-platform (COBOL, C++, Ada).
I do see individuals developing languages. Python and Ruby have strong followings. JavaScript is popular. I expect other individuals to create new languages for distributed computing. These languages will be simple, specific, and show little change over time.
I also see commercial vendors building languages. Apple recently introduced Swift. If they follow the trend for vendor-specific languages, we can expect changes to the Swift language, perhaps as often as every year (or with every release of MacOS or iOS). Microsoft is looking to build its cloud and mobile offerings; new versions of C# may be in the works. Oracle is working on Java; recent changes have fixed the code base and tools, new versions may change the language. Google is building Go and Dart languages. Can Google leverage them for advantage?
The Dart language is in an interesting position. It is a replacement for JavaScript and it compiles to JavaScript. It must remain simpler than JavaScript; if it becomes more complex, then programmers will simply use JavaScript instead of the harder Dart.
* * * * *
In short, I expect programming languages from vendors to change moderately rapidly. I expect programming languages from individuals to change less rapidly. Whether a programming language changes over time may affect your choice. You decide.
Tuesday, January 13, 2015
Functional programming exists in C++
Yet C++ programmers, if they look closely enough, can find a little bit of functional programming in their language. Hidden in the C++ specification is a tiny aspect of functional programming. It occurs in C++ constructor initializers.
Initializers are specifications for the initialization of member variables in a constructor. The C++ language provides for default initialization of member variables; initializers override these defaults and let the programmer specific actions.
Given the class:
class MyInts {
private:
int a1_;
int a2_;
public:
MyInts(void);
}
one can store two integers in an object of type MyInts. The old-style C++ method is to provide 'setter' and 'getter' functions to allow the setting and retrieval of values. Something like:
class MyInts {
private:
int a1_;
int a2_;
public:
MyInts(void);
void setA1(int a1) { a1_ = a1; };
int getA1(void) const { return a1_; };
void setA2(int a2) { a2_ = a2; };
int getA2(void) const { return a2_; };
}
private:
int a1_;
int a2_;
public:
MyInts(int a1, int a2) : a1_(a1), a2_(a2) {};
int getA1(void) const { return a1_; };
int getA2(void) const { return a2_; };
}
Initializers are interesting. One cannot do just anything in an initializer. You can provide a constant value. You can provide a constructor for a class (if your member variable is an object). You can call a function that provides a value, but it should be either a static function (not a member function) or a function outside of the class. (Calling a member function on the same class is an undefined operation. It may work, or it may not.)
These restrictions on initializers enforce one of the attributes of functional programming: immutable objects. In my example, I eliminated the 'setter' functions to may objects of MyInts immutable, but that was an intentional effect. I could have left the 'setter' functions in place, and then objects of MyInts would be mutable.
Initializers brook no such nonsense. You have one opportunity to set the value for a member variable (you cannot initialize a member variable more than once). Once it is set, it cannot be changed, during the initialization. You cannot call a function that has a side effect of changing a member variable that has been previously set. (Such a call would be to a member function, and while permitted by the compiler, you should avoid them.)
Initializers provide a small bit of functional programming inside C++. Who would have thought?
Technically, the attributes I have described are not functional programming, but merely immutable objects. Functional programming allows one to treat functions as first class citizens of the language, creating them and passing them to other functions as needed. The initializers in C++ do not allow such constructs.
Sunday, January 11, 2015
The answer is not a bigger computer
The power of virtualized computers is not in larger computers.
Traditionally in computers, bigger was better. When we had single mainframes managing the data for companies. a larger computer meant faster returns on reports and more powerful analyses. When we had personal computers on desktops, faster computers meant faster computations in spreadsheets.
When the unit of computing is a single device (a mainframe or a PC), then bigger is better (usually).
But with cloud computing, the unit of computing is not a single device -- it is the cloud itself, which consists of a number of devices. A variable number of virtualized devices, actually. Cloud-based systems are not single application programs running on single computers; they are systems of small programs running on multiple servers. The expansion capabilities of cloud are not based on a single computer. They are not based on expanding the processor, or increasing the memory.
Cloud computing expands by increasing the number of computers.
Looking for increased performance through more cores or more memory is not the "way of the cloud". If you have a large process, one that demands lots of processing and memory, then you are not doing cloud right.
Moving to cloud means re-thinking the way we build applications. It means systems assembled from services, not large monolithic programs. Look for the large processes and break them into smaller ones. It may not be easy. Our legacy systems were designed around single-device thinking, and optimized for single devices. To be successful in cloud computing, our thinking has to change.
Thursday, January 8, 2015
Hardwiring the operating system
I know that computers are complex objects, and each of these four components has lots of subcomponents. For example, the hardware is a collection of processor, memory, video card, hard drive, ports to external devices, and "glue" circuitry to connect everything. (And even that is omitting some details.)
These top-level divisions, while perhaps not detailed, are useful. They allow me to separate the concerns of a computer. I can think about my data without worrying about the operating system. I can consider application programs without bothering with hardware.
It wasn't always this way. Oh, it was for personal computers, even those from the pre-IBM PC days. Hardware like the Altair was sold as a computing box with no operating system or software. Gary Kildall at Digital Research created CP/M to run on the various hardware available and designed it to have a dedicates unit for interfacing with hardware. (That dedicated unit was the Basic Input-Output System, or 'BIOS'.)
It was the very early days of computers that saw a close relationship between hardware, software, and data. Very early computers had no operating systems (operating systems themselves designed to separate the application program from the hardware). Computers were specialized devices, tailored to the task.
IBM's System/360 is recognized as the first general computer: a single computer that could be programmed for different applications, and used within an organization for multiple purposes. That computer began us on the march to separate hardware and software.
The divisions are not simply for my benefit. Many folks who work to design computers, build applications, and provide technology services find these divisions useful.
The division of computers into these four components allows for any one of the components to be swapped out, or moved to another computer. I can carry my documents and spreadsheets (data) from my PC to another one in the office. (I may 'carry' them by sending them across a network, but you get the idea.)
I can replace a spreadsheet application with a different spreadsheet application. Perhaps I replace Excel 2010 with Excel 2013. Or maybe change from Excel to another PC-based spreadsheet. The new spreadsheet software may or may not read my old data, so the interchangeability is not perfect. But again, you get the idea.
More than half a century later, we are still separating computers into hardware, operating system, application programs, and data.
And that may be changing.
Tuesday, January 6, 2015
The cloud brings change
Before cloud technology, operations viewed hardware and software as things that should change rarely and under strictly controlled conditions. Hardware was upgraded only when needed, and only after long planning sessions to review the new equipment and ensure it would work. Software was updated only during specified "downtime windows", typically early in the morning on a weekend when demand would be low.
The philosophies of "change only when necessary" and "only when it won't affect users" were driven by the view of hardware and software. Before cloud computing, most people had a mindset that I call the "mainframe model".
In this "mainframe model," there is one and only one computer. In the early days of computing, this was indeed the case. Turning the computer off to install new hardware meant that no one could use it. Since the entire company ran on it, a hardware upgrade (or a new operating system) meant that the entire company had to "do without". Therefore, updates had to be scheduled to minimize their effect and they had to be carefully planned to ensure that everything would work upon completion.
Later systems, especially web systems, used multiple web servers and often multiple data centers with failover, but people kept the mainframe model in their head. They carefully scheduled changes to avoid affecting users, and they carefully planned updates to ensure everything would work.
Cloud computing changes that. With cloud computing, there is not a single computer. There is not a single data center (if you're building your system properly). By definition, computers (usually virtualized) can be "spun up" on demand. Taking one server offline does not affect your customers; if demand increases you simply create another server to handle the additional workload.
The ability to take servers offline means that you can relax the scheduling of upgrades. You do not need to wait until the wee hours of the morning. You do not need to upgrade all of your servers at once. (Although running servers with multiple versions of your software can cause other problems. More on that later.)
Netflix has taken the idea further, creating tools that deliberately break individual servers. By doing so, Netflix can examine the failures and design a more robust system. Once a single server fails, other servers take over the work -- or so Netflix would like. If servers don't pick up the workload, Netflix has a problem and changes their code.
Cloud technology lets us use a new model, what I call the "cloud model". This model allows for failures at any time -- not just from servers failing but from servers being taken offline for upgrades or maintenance. Those upgrades could be hardware, virtualized hardware, operating systems, database schemas, or application software.
The cloud model allows for change. It requires a different set of rules. Instead of scheduling all changes for a single downtime window, it distributes changes over time. It mandates that newer versions of applications and databases work with older versions, which probably means smaller, more incremental changes. It also encourages (perhaps requires) software to administer the changes and ensure that all servers get the changes. Instead of growing a single tree you are growing a forest.
The fact that cloud technology brings change, or changes our ideas of changes, should not be a surprise. Other technologies and techniques (agile development, dynamic languages) have been moving in the same direction. Even Microsoft and Apple are releasing products more quickly. Change is upon us, whether we want it or not.
Tuesday, December 30, 2014
Agile is not for everyone
Agile development is a hot topic for many project managers. It is the latest management fad, following total cost of ownership (TCO) and total quality management (TQM). (Remember those?)
So here is a little bit of heresy: Agile development methods are not for every project.
To use agile methods effectively, one must understand what they offer -- and what they don't.
Agile methods make one guarantee: that your system will always work, for the functionality that has been built. Agile methods (stakeholder involvement, short development cycles, automated testing) ensures that the features you build will work as you expect. Even as you add new features, your automated tests ensure that old features still work. Thus, you can always send the most recent version of your system to your customers.
But agile methods don't make very promise. Specifically, they don't promise that all of your desired features will be available (and working) on a specific date. You may have a list of one hundred features; agile lets you implement those features in a desired order but does not guarantee that they will all be completed by an arbitrary date. The guarantee is only that the features implemented by that date will work. (And you cannot demand that all features be implemented by that date -- that's not agile development.)
Agile does let you make projections about progress, once you have experience with a team, the technology, and a set of features for a system. But these projections must be based on experience, not on "gut feel". Also, the projections are just that: projections. They are estimates and not guarantees.
Certain businesses want to commit to specific features on specific dates, perhaps to deliver a system to a customer. If that is your business, that you should look carefully at agile methods and understand what they can provide. It may be that the older "waterfall" methods, which do promise a specific set of features on a specific date, are a better match.
Friday, December 26, 2014
Google, Oracle, and Java
Apple has a cozy walled garden for its technology: Apple devices running Apple operating systems and Apple-approved apps written in Apple-controlled languages (Objective-C and now Swift).
Microsoft is building a walled garden for its technology. Commodity devices with standards set by Microsoft, running Microsoft operating systems and apps written in Microsoft-controlled languages (C#, F#, and possibly VB.NET). Microsoft does not have the same level of control over applications as Apple; desktop PCs allow anyone with administrator privileges to install any app from any source.
Google has a walled garden for its technology (Android), but its control is less than that of Apple or Microsoft. Android runs on commodity hardware, with standards set by Google. Almost anyone can install apps on their Google phone or tablet. And interestingly, the Android platform apps run in Java, a language controlled by... Oracle.
This last aspect must be worrying to Google. Oracle and Google have a less than chummy relationship, with lawsuits about the Java API. Basing a walled garden on someone else's technology is risky.
What to do? If I were Google, I would consider changing the language for the Android platform. That's not a small task, but the benefits may outweigh the costs. Certainly their current apps would have to be re-written for the New language. A run-time engine would have to be included in Android. The biggest task would be convincing the third-party developers to change their development process and their existing apps. (Some apps may never be converted.)
Which language to pick? That's an easy call. It should be a language that Google controls: Dart or Go. Dart is designed as a replacement for JavaScript, yet could be used for general applications. Go is, in my opinion, the better choice. It *is* designed for general applications, and includes support for concurrency.
A third candidate is Python. Google supports Python in their App Engine cloud platform, so they have some familiarity with it. No one company controls it (Java was controlled by Sun prior to Oracle) so it is unlikely to be purchased.
Java was a good choice for launching the Android platform. I think the languages Go and Python are better choices for Android now.
Let's see what Google thinks.