I like the Ruby programming language. I've been using it for several projects, including an interpreter for the BASIC language. (The interpreter for BASIC was an excuse to do something in Ruby and learn about the language.)
My experience with Ruby has been a good one. I find that the language lets me do what I need, and often very quickly. The included classes are well-designed and include the functions I need. From time to time I do have to add some obscure capability, but those are rare.
Yet Ruby has a sharp edge to it, an aspect that can cause trouble if you fail to pay attention.
That aspect is one of its chief features: flexibility.
Let me explain.
Ruby is an object-oriented language, which means the programmer can define classes. Each class has a name, some functions, and usually some private data. You can do quite a bit with class definitions, including class variables, class instance variables, and mix-ins to implement features in multiple classes.
You can even modify existing classes, simply by declaring the same class name and defining new functions. Ruby accepts a second definition of a class and merges it into the first definition, quietly and efficiently. And that's the sharp edge.
This "sharp edge" cut me when I wasn't expecting it. I was working on my BASIC interpreter, and had just finished a class called "Matrix", which implemented matrix operations within the language. My next enhancement was for array operations (a matrix being a two-dimensional structure and an array being a one-dimensional structure).
I defined a class called "Array" and defined some functions, including a "to_s" function. (The name "to_s" is the Ruby equivalent of "ToString()" or "to_string()" in other languages.)
And my code behaved oddly. Existing functions, having nothing to do with arrays or my Array class, broke.
Experienced Ruby programmers are probably chuckling at this description, knowing the problem.
Ruby has its own Array class, and my Array class was not a new class but a modification of the existing, built-in class named "Array". My program, in actuality, was quite different from my imagined idea. When I defined the function "to_s" in "my" Array class, I was actually overwriting the existing "to_s" function in the Ruby-supplied Array class. And that happened quietly and efficiently -- no warning, no error, no information message.
Part of this problem is my fault. I was not on my guard against such a problem. But part of the problem, I believe, is Ruby's -- specifically the design of Ruby. Letting one easily modify an existing class, with no warning, is dangerous. And I say this not simply due to my background with languages that use static checking.
My error aside, I can think of two situations in which this can be a problem. The first is when a new version of the Ruby language (and its system libraries) are released. Are there new classes defined in the libraries? Could the names of those classes duplicate any names I have used in my project? For example, will Ruby one day come with a class named "Matrix"? If it does, it will collide with my class named "Matrix". How will I know that there is a duplicate name?
The second situation is on a project with multiple developers. What happens if two developers create classes with the same name? Will they know? Or will they have to wait for something "weird" to happen?
Ruby has some mechanisms to prevent this problem. One can use namespaces within the Ruby language, to prevent such name conflicts. A simple grep of the code, looking for "class [A-Z][\w]" and then a sort will identify duplicate names. But these solutions require discipline and will -- they don't come "for free".
As I said earlier, this is a sharp edge to Ruby. Is it a defect? No, I think this is the expected behavior for the language. It's not a defect. But it is an aspect of the language, and one that may limit the practicality of Ruby on large applications.
I started this blog with the statement that I like Ruby. I still like Ruby. It has a sharp edge (like all useful tools) and I think that we should be aware of it.
Showing posts with label ruby. Show all posts
Showing posts with label ruby. Show all posts
Tuesday, July 18, 2017
Sunday, January 10, 2016
Use the tools available
I've just completed some work on a small project. My success is due, not only to my own talent and hard work, but to the tools that were available to me.
The project was in Ruby, and the tool that assisted me was Rubocop.
Rubocop analyzes Ruby code and reports on questionable (but legal) constructs and syntax. It is, in a phrase, "lint" for Ruby.
Almost all of the major languages have syntax checkers. For C and C++, there is lint. For C# there is FXCop. For Python, PyLint. Even Perl has Perl::Critic and Perl::Lint.
Rubocop helped me, indirectly. I used it as I developed the project. I ran it on the code I was writing, and it reported that certain functions were "too long", according to its default guidelines.
Some programmers would be arrogant and refuse to heed such advice. (Myself at an earlier point in my career, for example.) But with the wisdom of experience, I chose to modify the code and reduce the size of functions. It was an investment.
When I modified the long functions, I broke them into smaller ones. This had the benefit of making duplicate code obvious, as some of the smaller functions performed identical tasks. (The large versions of the functions also performed these identical tasks, but the duplications were not apparent.)
I combined duplicate functions into single functions, and reduced the overall size of the code. I also created abstract classes to hold functions common to concrete derived classes.
The simpler version of the code was, well, simpler. That meant that subsequent changes were easier to implement. In fact, one particular feature had me worried, yet the simpler code made that feature easy to add.
Rubocop helped me simplify the code, which made it easy for me to add new features -- and get them right. Rubocop was a tool, a useful tool.
On your projects, be aware of the tools that can help you.
The project was in Ruby, and the tool that assisted me was Rubocop.
Rubocop analyzes Ruby code and reports on questionable (but legal) constructs and syntax. It is, in a phrase, "lint" for Ruby.
Almost all of the major languages have syntax checkers. For C and C++, there is lint. For C# there is FXCop. For Python, PyLint. Even Perl has Perl::Critic and Perl::Lint.
Rubocop helped me, indirectly. I used it as I developed the project. I ran it on the code I was writing, and it reported that certain functions were "too long", according to its default guidelines.
Some programmers would be arrogant and refuse to heed such advice. (Myself at an earlier point in my career, for example.) But with the wisdom of experience, I chose to modify the code and reduce the size of functions. It was an investment.
When I modified the long functions, I broke them into smaller ones. This had the benefit of making duplicate code obvious, as some of the smaller functions performed identical tasks. (The large versions of the functions also performed these identical tasks, but the duplications were not apparent.)
I combined duplicate functions into single functions, and reduced the overall size of the code. I also created abstract classes to hold functions common to concrete derived classes.
The simpler version of the code was, well, simpler. That meant that subsequent changes were easier to implement. In fact, one particular feature had me worried, yet the simpler code made that feature easy to add.
Rubocop helped me simplify the code, which made it easy for me to add new features -- and get them right. Rubocop was a tool, a useful tool.
On your projects, be aware of the tools that can help you.
Monday, June 22, 2015
Static languages for big and dynamic languages for small
I will admit, up front, that I have more experience with statically-type languages (C, C++, Java, C#) than with dynamically-typed languages (Python, Ruby). I learned C before any of the others (but after BASIC, Fortran, and Pascal) and learned Python and Ruby most recently. My opinions are biased, shaped by my experience, or lack thereof, with specific programming languages.
Now that we have the disclaimer out of the way...
I have found that I write programs differently in dynamically-typed languages than I do in statically-typed languages.
There are many differences between the two language sets. C++ is a big jump up from C. Java and C# are, in my mind, a bit simpler than C++. Python and Ruby are simpler than Java and C# -- yet more powerful.
Putting language capabilities aside, I have examined the programs I have written. I have two distinct styles, one for statically-typed languages and a different style for dynamically typed languages. The big difference in my two styles? The names of things.
Programs in any language need names. Even the old Dartmouth BASIC needs names for variables, and one can argue that with the limited namespace (one letter and one optional digit) one must give more thought to names in BASIC than in any other language.
My style for statically-type languages is to name variables and functions with semantic names. Names for functions are usually verb phrases, describe the action performed by the function. Names for objects usually describe the data contained by the variable.
My style for dynamically-typed languages is different. Names for functions typically describe the data structure that is returned by the function. Names for variables typically describe the data structure contained by the variable (or referenced by it, if you insist).
Perhaps this difference is due to my familiarity with the older statically-typed languages. Perhaps it is due to the robust IDEs for C++, Java, and C# (for Python and Ruby I typically use a simple text editor).
I find dynamically-typed languages much harder to debug than statically-typed languages. Perhaps this is due to the difference in tools. Perhaps it is due to my unfamiliarity with dynamically-typed languages. But perhaps it is simply easier to analyze and debug statically-typed languages.
If that is true, then I can further state that it is better to use a statically-typed languages for large projects. It may also be better to use a dynamically-typed language for smaller programs. I'm not sure how large 'large' is in this context, nor am I sure how small 'small' is. Nor do I know the cross-over point, at which it is better to switch from one to the other.
But I think it is worth thinking about.
Actually, I tend to write FORTRAN in all programming languages. But that is another matter.
Now that we have the disclaimer out of the way...
I have found that I write programs differently in dynamically-typed languages than I do in statically-typed languages.
There are many differences between the two language sets. C++ is a big jump up from C. Java and C# are, in my mind, a bit simpler than C++. Python and Ruby are simpler than Java and C# -- yet more powerful.
Putting language capabilities aside, I have examined the programs I have written. I have two distinct styles, one for statically-typed languages and a different style for dynamically typed languages. The big difference in my two styles? The names of things.
Programs in any language need names. Even the old Dartmouth BASIC needs names for variables, and one can argue that with the limited namespace (one letter and one optional digit) one must give more thought to names in BASIC than in any other language.
My style for statically-type languages is to name variables and functions with semantic names. Names for functions are usually verb phrases, describe the action performed by the function. Names for objects usually describe the data contained by the variable.
My style for dynamically-typed languages is different. Names for functions typically describe the data structure that is returned by the function. Names for variables typically describe the data structure contained by the variable (or referenced by it, if you insist).
Perhaps this difference is due to my familiarity with the older statically-typed languages. Perhaps it is due to the robust IDEs for C++, Java, and C# (for Python and Ruby I typically use a simple text editor).
I find dynamically-typed languages much harder to debug than statically-typed languages. Perhaps this is due to the difference in tools. Perhaps it is due to my unfamiliarity with dynamically-typed languages. But perhaps it is simply easier to analyze and debug statically-typed languages.
If that is true, then I can further state that it is better to use a statically-typed languages for large projects. It may also be better to use a dynamically-typed language for smaller programs. I'm not sure how large 'large' is in this context, nor am I sure how small 'small' is. Nor do I know the cross-over point, at which it is better to switch from one to the other.
But I think it is worth thinking about.
Actually, I tend to write FORTRAN in all programming languages. But that is another matter.
Monday, May 19, 2014
The shift to cloud is bigger than we think
We've been using operating systems for decades. While they have changed over the years, they have offered a consistent set of features: time-slicing of the processor, memory allocation and management, device control, file systems, and interrupt handling.
Our programs ran "under" (or "on top of") an operating system. Our programs were also fussy -- they would run on one operating system and only that operating system. (I'm ignoring the various emulators that have come and gone over time.)
The operating system was the "target", it was the "core", it was the sun around which our programs orbited.
So it is rather interesting that the shift to cloud computing is also a shift away from operating systems.
Not that cloud computing is doing away with operating systems. Cloud computing coordinates the activities of multiple, usually virtualized, systems, and those systems run operating systems. What changes in cloud computing is the programming target.
Instead of a single computer, a cloud system is composed of multiple systems: web servers, database servers, and message queues, typically. While those servers and queues must run on computers (with operating systems), we don't care about them. We don't insist that they run any specific operating system (or even use a specific processor). We care only that they provide the necessary services.
In cloud computing, the notion of "operating system" fades into the infrastructure.
As cloud programmers, we don't care if our web server is running Windows. Nor do we care if it is running Linux. (The system administrators do care, but I am taking a programmer-centric view.) We don't care which operating system manages our message queues.
The level of abstraction for programmers has moved from operating system to web services.
That is a significant change. It means that programmers can focus on a higher level of work.
Hardware-tuned programming languages like C and C++ will become less important. Not completely forgotten, but used only by the specialists. Languages such as Python, Ruby, and Java will be popular.
Operating systems will be less important. They will be ignored by the application level programmers. The system architects and sysadmins, who design and maintain the cloud infrastructure, will care a lot about operating systems. But they will be a minority.
The change to services is perhaps not surprising. We long ago shifted away from processor-specific code, burying they work in our compilers. COBOL and FORTRAN, the earliest languages, were designed to run on different processors. Microsoft insulated us from the Windows API with MFC and later the .NET framework. Java separated us from the processor with its virtual machine. Now we take the next step and bury the operating system inside of web services.
Operating systems won't go away. But they will become less visible, less important in conversations and strategic plans. They will be more of a commodity and less of a strategic advantage.
Our programs ran "under" (or "on top of") an operating system. Our programs were also fussy -- they would run on one operating system and only that operating system. (I'm ignoring the various emulators that have come and gone over time.)
The operating system was the "target", it was the "core", it was the sun around which our programs orbited.
So it is rather interesting that the shift to cloud computing is also a shift away from operating systems.
Not that cloud computing is doing away with operating systems. Cloud computing coordinates the activities of multiple, usually virtualized, systems, and those systems run operating systems. What changes in cloud computing is the programming target.
Instead of a single computer, a cloud system is composed of multiple systems: web servers, database servers, and message queues, typically. While those servers and queues must run on computers (with operating systems), we don't care about them. We don't insist that they run any specific operating system (or even use a specific processor). We care only that they provide the necessary services.
In cloud computing, the notion of "operating system" fades into the infrastructure.
As cloud programmers, we don't care if our web server is running Windows. Nor do we care if it is running Linux. (The system administrators do care, but I am taking a programmer-centric view.) We don't care which operating system manages our message queues.
The level of abstraction for programmers has moved from operating system to web services.
That is a significant change. It means that programmers can focus on a higher level of work.
Hardware-tuned programming languages like C and C++ will become less important. Not completely forgotten, but used only by the specialists. Languages such as Python, Ruby, and Java will be popular.
Operating systems will be less important. They will be ignored by the application level programmers. The system architects and sysadmins, who design and maintain the cloud infrastructure, will care a lot about operating systems. But they will be a minority.
The change to services is perhaps not surprising. We long ago shifted away from processor-specific code, burying they work in our compilers. COBOL and FORTRAN, the earliest languages, were designed to run on different processors. Microsoft insulated us from the Windows API with MFC and later the .NET framework. Java separated us from the processor with its virtual machine. Now we take the next step and bury the operating system inside of web services.
Operating systems won't go away. But they will become less visible, less important in conversations and strategic plans. They will be more of a commodity and less of a strategic advantage.
Labels:
C,
C++,
cloud computing,
operating systems,
programming,
python,
ruby
Saturday, January 7, 2012
Predictions for 2012
Happy new year!
The turning of the year provides a time to pause, look back, and look ahead. Looking ahead can be fun, since we can make predictions.
Here are my predictions for computing in the coming year:
Here are my predictions for computing in the coming year:
With the rise of mobile apps, we will see changes in project requirements and in the desires of candidates.
The best talent will work on mobile apps. The best talent will -- as always -- work on the "cool new stuff". The "cool new stuff" will be mobile apps. The C#/.NET and Java applications will be considered "that old stuff". Look for the bright, creative programmers and designers to flock to companies building mobile apps. Companies maintaining legacy applications will have to hire the less enthusiastic workers.
Less funding for desktop applications. Desktop applications will be demoted to "legacy" status. Expect a reduced emphasis on their staffing. These projects will be viewed as less important to the organization, and will see less training, less tolerance for "Fast Company"-style project teams, and lower compensation. Desktop projects will be the standard, routine, bureaucratic (and boring) projects of classic legacy shops. The C# programmers will be sitting next to, eating lunch with, and reminiscing with, the COBOL programmers.
More interest in system architects. Mobile applications are a combination of front end apps (the iPhone and iPad apps) and back-end systems that store and supply data. Applications like Facebook and Twitter work only because the front end app can call upon the back end systems to obtain data (updates submitted by other users). Successful applications will need people who can visualize, describe, and lead the team in building mobile applications.
More interest in generalists. Companies will look to bring on people skilled in multiple areas (coding, testing, and user interfaces). They will be less interested in specialists who know a single area -- with a few exceptions of the "hot new technologies".
Continued fracturing of the tech world. Amazon.com, Apple, and Google will continue to build their walled gardens of devices, apps, and media. Music and books available from Amazon.com will not be usable in the Apple world (although available on the iPod and iPad in the Amazon.com Kindle app). Music and books from Apple will not be available on Amazon.com Kindles and Google devices. Consumers will continue to accept this model. (Although like 33 RPM LPs and 45 PRM singles, consumers will eventually want a music and books on multiple devices. But that is a year or two away.)
Cloud computing will be big, popular, and confused. Different cloud suppliers offer different types of cloud services. Amazon.com's EC2 offering is a set of virtual machines that allow one to "build up" from there, installing operating systems and applications. Microsoft's Azure is a set of virtual machines with Windows/.NET and one may build applications starting at a higher level that Amazon's offering. Salesforce.com offers their cloud platform that lets one build applications at an even higher level. Lots of folks will want cloud computing, and vendors will supply it -- in the form that the vendor offers. When people from different "clouds" meet, they will be confused that the "other guy's cloud" is different from theirs.
Virtualization will fade into the background. It will be useful in large shops, and it will not disappear. It is necessary for cloud computing. But it will not be the big star. Instead, it will be a quiet, necessary technology, joining the ranks of power management, DASD management, telecommunications, and network administration. Companies will need smart, capable people to make it work, but they will be reluctant to pay for them.
Telework will exist, quietly. I expect that the phrase "telework" will be reserved for traditional "everyone works in the office" companies that allow some employees to work in remote locations. For them, the default will be "work in the office" and the exception will be "telework". In contrast, small companies (especially start-ups) will leverage faster networks, chat and videoconferencing, mobile devices, and social networks. Their standard mode of operation will be "work from wherever" but they won't think of themselves as offering "telework". From their point of view, it will simply be "how we do business", and they won't need a word to distinguish it. (They may, however, create a word to describe folks who insist on working in company-supplied space every day. Look for new companies to call these people "in-house employees" or "residents".)
Understand the sea change of the iPad. The single-app interface works for people consuming information. The old-fashioned multi-windowed desktop interface works for people composing and creating information. This change leads to a very different approach to the design of applications. This year people will understand the value of the "swipe" interface and the strengths of the "keyboard" interface.
Voice recognition will be the hot new tech. With the success of "Siri" (and Android's voice recognizer "Majel"), expect interest in voice recognition technology and apps designed for voice.
Content delivery becomes important. Content distributors (Amazon.com, Google, and Apple) become more important, as they provide exclusive content within their walled gardens. The old model of a large market in which anyone can write and sell software will change to a market controlled by the delivery channels. The model becomes one similar to the movie industry (a few studios producing and releasing almost all movies) and the record industry (a few record labels producing and releasing almost all music) and the book industry (a few publishing houses... you get the idea).
Content creation becomes more professional. With content delivery controlled by the few major players, the business model becomes less "anyone can put on a show" and more of "who do you know". Consumers and companies will have higher expectations of content and the abilities of those who prepare it.
Amateur producers will still exist, but with less perceived value. Content that is deemed "professional" (that is, for sale on the market) will be developed by professional teams. Other content (such as the day-to-day internal memos and letters) will be composed by amateur content creators: the typical office worker equipped with a word processor, a spreadsheet, and e-mail will be viewed as less important, since they provide no revenue.
Microsoft must provide content provider and enable professional creators. Microsoft's business has been to supply tools to amateur content creators. Their roots of BASIC, DOS, Windows, Office, and Visual Basic let anyone (with or without specific degrees or certifications) create content for the market. With the rise of the "professional content creator", expect Microsoft to supply tools labeled (and priced) for professionals.
Interest in new programming languages. Expect a transition from the object-oriented languages (C++, Java, C#) to a new breed of languages that introduce ideas from functional programming. Languages such as Scala, Lua, Python, and Ruby will gain in popularity. C# will have a long life -- but not the C# we know today. Microsoft has added functional programming capabilities to the .NET platform, and modified the C# language to use them. C# will continue to change as Microsoft adapts to the market.
The new year brings lots of changes and a bit of uncertainty, and that's how it should be.
Subscribe to:
Posts (Atom)