пятница, 20 июля 2012 г.

Learning to Program

About a year ago I took part in a vivid discussion of the best choice of the first programming language to study. The discussion didn't lead to any consensus thus making me think a lot about the question itself as well as remember the path along which I moved through the land of the programming craft.

I began studying programming during my first year in university. Thanks to chosing the speciality which is closely related to software, I had a course of C programming language right in the first semester. That time I wasn't aware of numerous programming languages that are used for creating software - I have heard about some, but, nevertheless, I was sure that the only important ones are C and C++ (by the way, I didn't actually understand the difference between the two). In fact by the time when I was enrolled to university I had already got some minor experience with basic features of C like branching and looping statements and had written several extremely simple programs, although I didn't understand the way in which these things may produce any real piece of software. Furthemore, I knew hardly anything about the processes that run under the hood of computer and about it's structure. Thus I thought that I merely lacked knowledge of some special, more complex language features that allow creation of the beauty and complexity of, say, video games. Obviously that was a mistake and a very serious one, but much time passed before I finally recognized the fallacy. So going to the university I hoped that the secret knowledge would be opened to me and hence I would be able to produce astonishing things like my own Diablo 3 in a matter of months. Instead after the first weeks of study had passed I noticed that I was doing other things like studying binary numbers representation along with binary arithmetics, writing a program that prints a part of Fibonacci sequence to console or finds a minimal number in an array. In addition to this I tried to understand the derivation techniques, memorized the Koshi Theorem, realized what do the words 'rank of matrix' mean and struggled to produce three projections of a cone intersecting a thorus on an A3 sheet. Still I thought that this stuff is somehow useful and may provide some help when the real Arcane knowledge would be shared with me. Then came the second term with another Calculus, Physics, Mechanics and Object-oriented programming in C++. By it's beginning I was sure that my teachers would continue maliciously hiding from me the things I wanted to know and, partially because of that I lost the eagerness to study all the disciplines that were claimed important. I should have taken control over my education and fought my own way to the desired knowledge, but unluckily I discovered a nasty thing named World of Warcraft. The discovery helped me waste about a year and a half of my time which I spent playing the MMORPG and doing other things quite irrelevant both to study and programming. This must have impacted my situation in university and finally it did in quite a predictable manner - I failed to pass the fourth session of exams concluding the second year of study and was expelled from university.

By the time when my expellation became a fact I had already ceased playing WoW and made some other minor changes to my lifestyle and habits. Moreover despite almost two years of living rather stupid life I have somehow managed to preserve the desire to learn how to write meaningful programs and to create software that solves real problems - it was kind of sleeping under the dust of my thoughts about playing video-games and hanging out with friends, so when I made an effort to change my life a bit this desire got naked and awaken.

Here the fact that I was expelled helped a lot - besides being a significant turning in my life that prompted me to rethink my decisions and views, it also left me no choice except for studying programming in my own if I wished to study it. Moreover, I had a lot of time as well as freedom to chose what to study and how to do it. Because of knowing that C and C++ languages are very popular and powerful and having some basic experience with them I didn't try to learn any other language - instead I decided to get closer to what I considered real programs via producing a component present in most applications that I used myself - the Graphical User Interface or GUI. The rightness of such a decision may be questioned, but for me it turned out to be an extremely valuable one and helped significantly in future. For that purpose I bought a book on Win32API programming. Actually I could have chosen any other much easier way to produce GUIs and Windows applications, but mainly do to the lack of insight I have picked a very low-level toolset bearing a huge amount of complexity and details and requiring a lot of efforts to explore them at least paritally. Besides that, the choice let me stay in the domain of low-level C and C++ languages - I could have left these before developing even the minor understanding of the concepts upon which C++ programming is based, should I chose some other tools like .NET that time. Later my experience with WinAPI helped with consuming different APIs - after using WinAPI cyclope most APIs seem rather simple and convenient - as well as provided some insight into the structure of operating systems. Although, I don't think that these things are the most important results of my attempts to use WinAPI.

I didn't work a lot with WinAPI actually - that is I did spend much time trying to scratch it's surface with my code and reading textbooks that explained it's features, but I haven't produced any significant results, any program that I could consider valuable now. Nevertheless, I think that I walked the right way at least because I finally managed to create something that felt meaningful to me. That was a pretty simple game where a player observed a field of hexagons of different colors and had to make them share a single color - I can't fully recall the mechanism of sharing now, but I remeber it was based on the notion of memebership and some other very simple things - anyway it's not important now. Sincerely speaking, I haven't really produced the game - the rules were not rigorously defined, there were no levels except for random one, no points that could be used to rank player's results - so the game wasn't a finished product of any kind, merely a sketch. Moreover, even the simple idea behind the game was borrowed from a Flash-based application that I spotted on some forum. The value of the game was of another kind - that was a thing produced by my own hands and at the same time that was something that I could play with. I could click my hexagons and they changed their colors according to the rules that I had imprinted into them, I could change the rules if I wished and immediately observe the different behaviour. Or rather I could come across a situation where the hexagons behaved in an unexpected way and spend some time searching for an erroneous line of code, fix it and see how the situation improved - or notice another bug. These almost godlike abilities amazed me and let me understand that all the complexity seen in real software is produced by the same basic tools - just combined in more complex ways. That time I came quite close to the truth.

The most important about my attempts to create this simple game were not programming and GUI building themselves, but the experience of creating rather complex thing guided by the rules that I had imposed on it and capable of interacting with me. I suppose that these two factors - namely, the complexity and the user interaction features - are of great importance when one learns how to create software. It is usual to study programming (as well as everything else) via doing numerous relatively simple tasks - and that's OK - but, from my point of view, it is also important to jump to something solid and complex as soon as one feels accustomed to key features and concepts of programming. Real things do consist of simple components, although usually the complexity of relations and interactions between the components is what makes the whole piece real. As for user interactions, these combined with complexity make programs look alive and that pays a lot to the creator. Note that I don't mean a GUI is required for making software interact with user - such an ability may also be delivered by means of simple console input and output - I merely state that it is reasonable to try to make your program capable of "speaking" to it's user, of paying attention to his actions. The experience of creating a program possessing these qualities of being moderately complex and able to more or less vividly interact with something beyond it's boundaries may be the thing that made me truly love programming.

My journey to the kingdom of WinAPI and GUIs continued with attempts to create a hex viewer. In fact I wanted to produce an editor, but I have wisely decided to implement something capable at least of showing the hex represnetation of file contents in the first place and then extend it. The task is quite easy to complete if one relies on multiple built-in controls such as Text Box, but I wanted to gain understanding of the low-level things so the decision was made to implement the main text field manually, using no control elements. Lacking discipline and experience I got buried under my own poorly structured code that loaded the binary content of a file, transformed it into hex characters, showed these in a window, managed scrolling and so on. The thing did display the proper characters grouped into columns of 4 bytes, but there were dozens of issues. Finally, after failing to inject a feature of selecting a desired sequence of bytes I gave up the project - mainly due to the feeling that to deliver editing functionality I need to rewrite everything from scratch. After all, although I was eager to create a finished piece of software, my main purpose was to understand how such things can be implemented and to gain experience. While the achievement of the former is questionable, the latter was definitely reached.

The failure to achieve one of my goals was a reason for giving up the attempts to master WinAPI, but it wasn't the only one - by that time I've started to explore new territories. I still wanted to understand how are videogames created and after getting used to basic ideas of programming I could imagine how can one implement logic of a game, bu I had no idea about producing graphics. I aknowledged that creating impressive graphics for a game requires doing the artists' stuff and I knew that I am not an artist at all, but it was very important for me at least to understand the programming tools that are used to make a game look like a videogame - not like Dungeons'n'Dragons or GURPS. That's why when I spotted a book on OpenGL in a book-store I bought it without a moment of hesitation. That same time I also bought 'The C++ Programming Language' by Bjarne Stroustrup - in fact this one was the reason for paying a visit to the store. So I spent a month or two exploring graphics programming with OpenGL and reading the Stroustroupe's magnificent book and thanks to the latter my programming attempts became more object-oriented, although the real dive into object-oriented programming remained ahead. By the time of purchasing these two books I have already resumed the study in university and even passed the fifth session of exams - in fact I did my research of OpenGL during the sixth one and it helped make the preparation for exams less boring. At the same time I was still eager to do something that would seem important not only to me and hence I asked one of our teachers for some programming task and quickly got one. Moreover with the task I received a recommendation to use C# programming language for it - the language I knew nothing about. Although I was unwilling to deviate from C++, I've managed to push myself to another trip to the bookstore and purchased a book on C# and .NET by Andrew Troelsen. This way the summer following the third year of study was devoted to studying the new programming language.

While my experience with C++ and WinAPI made exploring C# rather easy, two aspects distinguished programming in C# from the programming that I did before. First, C# involves automatic memory management and does it's best to free programmer from any concerns about memory - particularly via the absence of pointers. Making my first attempts with this language I really lacked pointers and sometimes was sure that if I had pointers some particular goal would be much easier to achieve - later I realized that commonly a programmer who writes code in C# doesn't need to do things that are difficult to do without pointers while the difficulties that I had faced don't emerge if one really does object-oriented programming and understands what the words "by-reference semantics" mean. Another thing that was unusual for me was the presence of .NET framework itself. Unlike C++, C# runs on a virtual machine and because the goals of virtual machine include freeing a programmer from low-level interaction with operating system it provides numerous built-in tools for doing OS-related work. Moreover there is huge amount of tools for achieving different higher-level targets like, say, communicating with remote machine by means of SOAP protocol which was a part of my task. These features seem to me the key factors making C# a language of a higher level than C or C++, that is a language that focuses on making the life of a programmer easier. However one must always keep in mind the fact that this advantage is achieved at the expense of control over the machine and of software performance.

Studying C# and working on the task received from my teacher impacted the programmer in me significantly. The high-levelness of the language led me to the idea that programming doesn't mean merely telling the machine what to do - instead it means describing the task and the solution to it in such a form that a machine can transform this description into series of operations. I've realized that there is a lot of room for a hierarchy of such descriptions freeing the programmer from concerns about the lower levels of his tasks when he implements the ideas of the higher level. This notion appeared to me in a form suggesting that when creating software one has to develop a hierarchy of "languages" capable of expressing the notions which a relevant to the task on different levels. Roughly speaking, the verbs of such a language represent the actions carried out on the corresponding level and are mapped to methods or functions which programmer writes, while the nouns mapped to objects, if we speak of object-oriented programming, are the things that act or are acted upon on the same level. The need for hierarchy of these languages suggests that each language is formulated in terms of the languages that reside below it, thus concealing the lower-level terms and ideas from the consumers of higher levels. These ideas helped me better separate the process of designing the things which I wanted to create from the process of writing code. That immediately led me to better designs and hence significantly simplified coding. At the same time the notion of creating languages and descriptions forced me to explore the ideas of Clean coding perfectly explained by Robert Martin in his 'Clean Code' book. Although all these gains were not the direct consequences of moving from one language to another, they were enforced by the corresponding switch to the higher level of thinking about the things that I did.

From the other side the discovery of a new programming language opened my mind to the whole new world of programming paradigms and languages freeing me from the fallacy suggesting that the only real programming is fighting machine with the hammer of C and the axe of C++. I don't mean that I've turned away from these powerful languages - I've merely noticed that there are dozens of other tools that rather frequently suit one's needs better than those which I believed to be the only weapons in programmer's arsenal. This awakening was further supported by an incentive of several my fellow students. Those guys studied on different faculties in my university but had one thing in common - they all were fond of programming and math and wanted to communicate with other students who shared the same interests - for this purpose they tried to estabilish a club of programmers. The idea was very simple: you just let the students know that every week there is a meeting where one can listen to other students describing their programming experience, speaking of interesting problems and solutions, showing the tools they find helpful for a programmer - or rather one may make his own report if he wants to share his knowledge. Besides, numerous challenges were hosted like problem sets that we tried to solve between meetings and then discussed or even the competitions during which we made up small teams and strived to complete some task within a proposed time limit. So the main goal of this club was to make programming even more interesting than it was and to provide the very important possibility of sharing experience. There is no surprise that these meetings showed me many new languages and tools - for instance, there I have heard for the first time of Mercurial revision control system which I widely use now - as well as gave me first insights into various problems and ideas of Computer Science. While studying the famous Gang of Four book on object-oriented design patterns I have even made a report that covered the main ideas behind the software design patterns and briefly described some of them. Honestly speaking, the report was poor - I'm still very bad in talking and communicating ideas to an audience - but it made me thoroughly study the subject and thus better understand it. The best way to develop good understanding of something lies through attempts to explain it to others - that's a well-known idea. Definitely the club brought a lot of fun into my life. 

Meanwhile, despite writing a lot of code in C#, I still retained my interest in C++ and decided to improve my skills by completing some task involving usage of basic C++ templates. I have chosen to implement a simple class representing Moore machine and support it with a small set of more or less useful utilities. Shame on me, I can't precisely remember what were it's template parameters - that must have been the types of state machine's output and input, but I may have also tried to parameterize the class over something stranger. Not surprisingly, I tried to incorporate my fresh knowledge of design patterns into this humble project and to make my code as clean as possible. Moreover, thanks to Uncle Bob, I have ]discovered the test-driven approach to software development. One chapter that stressed the importance of having a set of automated tests for every piece of software being developed was enough to make me believe in the power of at least unit tests. So the FSM project was extended with a collection of tests created by means of gtest library. These have not only helped to discover numerous errors in my code, but have also showed me some difficulties with consuming my tools, hence making me change their interfaces or structure in some cases. Another interesting word that I came across while reading Uncle Martin's book was 'refactoring'. Luckily my C# project mentioned above offered a great opportunity to grasp the meaning of the word. The attempts to improve both the design and the code structure took me a month or two - the result seemed unbelievable in comparison with the wasteyard that the project resembled before refactoring. However now, after a year has passed, I'm looking forward to a new iteration of refactoring required to include some components of this project into the new one - that promises another amazing adventure.

As I have noted, studying C# and attaining the meetings of our programmers club allowed me to notice the availability of various great programming languages and moreover made me consider trying some of these. This way before leaving to a month-long vacation on Cyprus last August I had downloaded python interpreter to the laptop that I carried there. The reason for choosing python as the next language to explore was usual - I've heard a lot about it: python is a very popular programming language and praticularly it is popular among the members of our club. Besides that, this language is deemed simple for studying, so it seemed a perfect candidate for injecting a slight measure of programming into my long vacation - I somehow felt that I need a possibility to have some rest from sea, beach, pubs, English classes and all other pleasant things that awaited me in the Mediterranean. The way that I have chosen to explore the new language was also quite common - a simple task hardly bearing any significant purpose though allowing to get familiar with basic features of python was set and I started doing it with the help of the language documentation. The only unusual thing about my first dive into python as compared to my first steps in other languages was the fact that I studied it on the balcony of my hotel-suit in Limassol after lunch and before a visit to the beach in evening. As for python itself, I had truly fallen in love with it and used it for solving almost every programming task in university during the next two semesters as well as for some other problems.

A nice thing about python - the one that, I think, makes the language very popular among scientists and that made me it's fan - is the fact that one doesn't need to do any extra work when one uses python, that is you are absolutely free to focus on the problem that you are trying to solve. For example, if you have a description of some algorithm, you just go and code it and the programs that are produced differ only slightly from the initial description. Honestly speaking, I can't name the features that make python easier to use than, say, C# - that may be the fact that python is an interpreted language, the duck-typing, the absence of parenthesis - maybe even the python's command prompt plays an important role here. Anyway, I'm quite sure that python is a language of a significantly higher level than even C# and Java. I think that the best evidence for this is the fact that python is used in most courses on Udacity education platform, some of which I am taking these days.

Finishing the list of programming languages that I have already tried I should mention two more. The first one is Java - I'm doing most of my job in it now. It is interesting that I wrote my first lines of code in Java only about a month or two ago, though now I feel very comfortable with the language. Such a quick start in fact isn't of any surprise considering the fact that Java is analogous to C# that was initially built on the ideas of the former. From the other hand, after discovering all these languages and getting used to object-oriented programming it was difficult to escape the temptation of the functional programming paradigm. In a rather random manner I have chosen Clojure for this purpose. Having already made my first steps with this interesting language I am now looking forward to creating a simple tool by it's means. Hopefully, it will help me get some understanding of the key ideas of functional programming which is extremely popular nowadays.

The story above suggests that I was moving more or less from the low-level languages to those of higher level, but it misses a detail that seems important to me. The same summer during which I was studying C# I discovered lots of courses offered by University of California: Berkeley in the form of webcasts and tried one of those. That was the CS61c course taught by impressive Dr. Dan Garcia that covered such topics as C programming language, assembly languages and computer structure. Later I had a course devoted to computer architecture involving some simple excercies in assembly languages in my university. Both courses helped me better understand the processes running behind the scenes of my programs, thus making me write better ones - at least I like to think this way.

As for the question about the best programming language to start from which, as you may have guessed, was raised during a meeting of our programmers club, there is no unique answer - not surprisingly the answer depends on the purpose of the one who choses the language. From one side, such a person may want to use programming as a tool that can provide some help in dealing with different tasks which are not directly connected to creating software - this approach seems to me usual for scientists. From the other hand, programming may be interesting for someone because he want's to produce software - that is become a software developer. For me it is obvious that these people do two very different kinds of programming because they pursue different goals. 'Scientists' usually create programs that either make computer do some work for them or in any other way shed light on things that are important for them. Thus 'scientists' ' programs are mainly intended for internal usage and are not considered shipped product and it is most important for a 'scientist' to create programs which produce meaningful results and to do that as fast as possible and with minimal effort devoted to writing code. That's why modern high-level languages - namely python - are so popular among folks who do science. Besides python, scientists also tend to chose mathematical programming environments like Matlab which are very convenient for people doing a lot of math. I suppose, that something as high-level as python is the best choice for a 'scientist' who commonly doesn't want to deviate to far from his field and targets.

The guys who develop software play absolutely another game of programming. Their goal is to deliver reliable and efficient products that perfectly suit their customers' needs. To achieve this goal developers need to understand deeply all the mechanisms on which their software relies. That's why I think it is very important for a software developer to have some experience with low-level languages like C and maybe even with assembly languages. Because after starting development in language like Java it may be rather difficult to make oneslef go to the lower level, I believe C is the best choice of the first programming language for a person who wants to develop software. Then, after getting familiar with C and thus developing some understanding of the stuff that underlies any piece of software, one is free to gradually move to the higher levels. Such an approach has a significant advantage over it's 'top-down' counterpart - it is in fact very easy to write first programs in, say, Java for a programmer who has written much code in C, while accustoming oneslef to C after using high-level languages may pose various difficulties which are strnghtened by a lack of motivation for studying low-level programming languages. The fact that my way from the low-level to the higher ones was very long and wavy shouldn't discourage anybody from stepping into this 'bottom-up' adventure - it is actually very easy to do it much faster than I did if one wants to become a great software developer and isn't afraid of difficulties of any kind. Hopefully my story highlights some of these difficulties hence making it easier to overcome them.

Although during the discussion we didn't come to a consensus about the best programming language to start from, it was easy to reach a consensus of another kind: any way that leads to becoming a good programmer - either a 'scientist' or a 'developer' - inevitably lies through writing many programs. So that's the thing one should do, no matter what language one has chosen to begin with.

Комментариев нет:

Отправить комментарий