A lot of these links are about how to get started coding. I am already a good programmer, maybe a damn good programmer. But I know there’s a level above mine, and probably several. How do I get to the next level? What does the next level look like? Are there any resources that talk about how to become a great programmer?
Learning the commands of my first programming language.
Learning the concepts of “if-when-else” and “while”.
Using functions to manage programs with more than dozen lines.
Using multiple files to manage programs with more than dozen functions.
Realizing the importance of writing good documentation.
Cooperating with other people on the same project.
Using directories and projects to manage programs with more than dozen files.
Realizing the importance of reading the specification.
Learning design patterns.
Realizing the importance of using the right tools for the job.
Learning refactoring.
Testing my code.
Seeing my code as a web of functionality, instead of a list of text files.
Learning a few new programming languages, and using parts of their style in other languages.
Designing architecture of a large project.
Leading other people in a project. (not completed yet)
Keeping focus on Getting Stuff Done. (not completed yet)
Each one of them could be a topic for a separate discussion. Some of them have this zen-like aspect that you first learn about a concept (e.g. object-oriented programming) and you use it everywhere; then at some moment you start to understand where it provides value and where it does not, and then you use it less. Stuff that once felt like the essence of programming gradually becomes just another tool in the box, to be used or replaced when necessary: you don’t have to use this specific library, this specific programming language, or this specific programming style.
The “social” skills (cooperating, leading), are not programming per se, but they will force you to use the other skills more carefully, because every mistake will hurt you tenfold.
Things that helped me:
Learning about formal languages at university. I would probably never learn it alone, because it seems so abstract. Most self-taught programmers don’t learn this. But for a certain kind of problems (text processing: parsing data files, evaluating expressions, interpreting or compiling a language) it gives you the magical skill of looking at the problem and almost instantly seeing that “this problem belongs to this category of problems, and these are the standard tools to solve it; the tools for a different category would fail because so and so”.
Learning different programming languages. The new languages introduce new concepts, but sometimes they show how the concepts which seemed essential in other languages can be avoided or done differently. -- I don’t need line numbers outside of old versions of Basic. I don’t have to make data type a part of the variable’s name if I use static typing. The data types are not only for the compiler to determine the variable size in bits, but they can describe the meaning of the value. I don’t have to use complicated variable names, if the scope of the variable is limited. In Java I use interfaces to describe what the class does, and extend classes to specify how. JavaScript and Lua allow object-oriented programming, and they don’t even have classes. A function is just another type of value, and it can be stored in a variable. Functional languages do not even allow changing the value of a variable, and you still can do what you need. You can write a program to generate a program. You can make your own programming language. All Turing-complete languages are equivalent, so at the end what really matters is the convenience of use.
Reading the original documentation, as soon as you are able to understand it. For information about HTML, read W3C specifications, and avoid w3schools. For information about Java, read Java Language Specification and tutorials made by Sun. Most online tutorials are written by people who don’t really understand the topic, they just learned it yesterday, and today they are trying to make some fame and adsense money from sharing their confused thoughts. (Especially everything related to PHP. Also PHP itself.) If most programmers are on the level zero, there will be many level-one gurus, and level-two system architects.
These kinds of recommendations are good, but not exactly what I was looking for, probably because they are a bit too high-level. Let me give you an example of the types of things I think have made me an incrementally better programmer recently:
Using a scripting language (Jython or Matlab) in combination with a compiled language (Java) to get the best of both approaches. One-off, adhoc analyses or jobs can be quickly developed in the scripting language, and then either thrown away or migrated to the compiled language if they prove to be useful. The ability of a tool like Jython or Matlab to script Java objects means that you can reuse your highly polished object logic in the scripting language.
Enforcing a “no-cycles” rule in my list of object and package dependencies. A full build of my code compiles package-by-package, so that if package A is ordered before package B in the list, package A cannot refer to package B. This is a good straitjacket to put yourself in, but I actually take it a step further and require that there cannot be circular object dependencies within a package.
A “smart” fast compilation script that checks if a source file has been modified and then recompiles just that file. This is actually kind of fast and loose in the sense that it can introduce bugs if you’re not careful.
Extensive use of assertions. Assertions actually serve two purposes—the obvious purpose of producing a “fail-fast” effect so that the code breaks immediately and for a clearly specified reason when the assertion fails. But they also serve for self-documentation. For example, say you are using a method that takes two arrays, one of size NxM and the other of size NxP. This introduces the potential for bugs if the array sizes don’t line up and also confusion if the caller can’t figure out whether s/he needs to pass an array or its transpose. Putting in the appropriate assertion both prevents confusing error messages but also indicates to the reader what the correct array sizes are.
Figuring out how to rely on the compiler more to catch potential errors at compile time. By writing code in a certain way, you can be more confident that IF there is an error, the compiler will catch it. One principle here is to use methods with mixed signatures—it’s better to have mymeth(String, int, boolean) than mymeth(String, String, String) because in the latter case the compiler won’t be able to catch it when you pass the arguments in the wrong order. Using enums is also a good idea.
Use of AutoHotKey to remap common commands to keyboard shortcuts that are easier on the fingers. For example, I remap cut and paste operations to the function keys, because I don’t like stretching my left pinky finger all the way out there to hit the control key.
Some things I need to get better at:
I need to know more about Unix. I have been procrastinating on taking the plunge and switching over to Linux for personal use.
Overall I need to have a more efficient computing environment—not just the programming language but the full ecosystem of tools: editor, shell, scripting language, keyboard, etc. (Aha, I just realized that I want my shell to produce sounds or music to supplement the text output so I can actually hear it if a program is behaving improperly).
I need to get better at building modular parameterized components and reusing them to build more complex applications. The Unix pipe-output-to-input is the model here, but it doesn’t do all the things I need it do. I can imagine a visual “wiring diagram” tool here (maybe similar to SpaceChem) that allows the user to hook up programs to each other, using basically the same piping idea, but in a more flexible way.
I should be able to make better estimates both for how long various process will take and how long they should take if my code were perfectly efficient (i.e. how close am I getting to the actual physical limitations of the hardware).
I should get better at using code analysis tools to detect errors. One thing that constantly annoys me is variable shadowing, and that should be possible to detect automatically ( I know some IDEs do this. I have mixed feelings about IDEs).
I am a big fan of IDEs, because they can remove a lot of trivial (or not so trivial) inconveniences.
I point a mouse cursor at any variable / function / class, and a documentation is displayed; if I press Ctrl and click, the definition is opened. What is the alternative: Remembering everything?
I often rename my variables / functions / classes, because I believe that the name should reflect the meaning as closely as possible, but sometimes when I finish writing something, I realize the meaning is slightly different than I originally thought. IDE replaces all instances of the given thing, but does not touch other things with the same name (e.g. a local variable in a different function, or a method of a different class). What is the alternative: Always thinking hard about the name? Leaving the old name even when it feels wrong? Check carefully whether only the correct words are being replaced?
Generally, when I work with a good IDE, I am not just editing a set of text files, but I feel like I am working with the generated classes and functions directly. Because it is so responsive, it feels more real. When I work without the IDE (or with a bad IDE), it feels very clumsy. For example, I can type “my_obj.my_func()” on the keyboard, but I don’t get an immediate response whether an object “my_obj” exists, whether it has a function “my_func”, whether the function has zero parameters. The IDE gives me this feedback all the time, it feels so natural, and I become tense without it. Sure, I can get the feedback later, from the compiler. But that’s like a difference between walking with open eyes, and walking with closed eyes and shortly looking around once in a minute. I can still successfully navigate to my goal, it just takes a heavy tax on my attention.
My favourite IDE is Eclipse, for Java. In settings it has a long list of things some people consider bad programming style, and you can select which of them will be underlined in the source code as warnings. Just reading the whole list is interesting. Once I tried to turn on all of them and then improve my program to fully pass the test. (Then I turned off one setting. It required localizing all the strings in code; that would be an overkill.) I learned some interesting things from that. But this could be achieved also by using an external tool, such as FindBugs or PMD.
require that there cannot be circular object dependencies within a package.
How do you avoid circular dependencies between e.g. “a node is a branch or a leaf” and “a branch contains two nodes”?
I agree with the other things (with the sidenote that some IDEs give you smart compilation and keyboard shortcuts automatically). The idea of an acoustic feedback sounds interesting!
If you want to develop your *nix skills, switching to Linux for personal use will not be as much help as you think. The most sure-fire way of picking up Linux chops is having to work with a core installation you can only access through the command line.
This is all good, but also just stuff that gets you from a neophyte to a competent programmer. What about the part where you want to get from the competent programmer level to the John Carmack, Peter Norvig and Oleg Kiselyov level?
You could ask them. But someone got to that level first, how did they do that?
Let’s suppose my goal is to become so cool that I could code StarCraft 3 during a weekend… without all the textures and levels and music and movies; just with some sample data, so my minions can later provide the rest. This would make me rather happy. :D
I could just spend one weekend doing my best, which obviously would not be enough. Then I could reflect on what was wrong. What was really slowing me down. I could try to research a solution for that (there is always a high prior probability that someone else already did it), or try to solve the problem myself. If I found I was missing some specific skill, I would focus on improving that skill.
The next test weekend, I could start again from the very beginning—more precisely, I would not reuse the specific code that I wrote the previous weekend; however, if in meantime I have prepared some useful library for myself, I would use that. The idea is that I am not unnecessarily handicapping myself; I am just assuming that what I did previously was wrong, so I am not going to build on my mistakes, but to do it right. Also, by always starting again I could get some feedback on whether this weekend I was really more effective than the previous one.
All Turing-complete languages are equivalent, so at the end what really matters is the convenience of use.
Well, any Turing complete language can implement a sort, but not every language can implement a sort in O(n log n) time, or a sort that uses O(log n) additional memory. Sorry, just being nitpicky.
True, though any turing-complete language can definitely, provably implement a sort that uses O(n log n) + k time or uses O(log n) + k additional memory (or straight-up all of them can do O(log n) memory if they have hard drive write access and OS auth to run other programs). “k” here is the amount of time it takes for this program to write and compile a compiler for some other, more efficient language, and then write the algorithm in that language, compile, and then run that.
At the extreme, the program could be an AI specialized in figuring out how to code the most efficient sorting algorithm given certain hardware specs, then figure out the most efficient language to write that in, then write it, then save it, then run it and delete itself.
Obviously, this is far, far from being convenient or efficient.
My comment viewed a Turing complete language as a sort of self-contained mathematical thing, which doesn’t necessarily have access to the operation “ask the OS to run this sequence of x86 instructions”. When people talk about Turing equivalence, that’s typically the meaning they use.
Interpreting one language in another is okay, but interpretation doesn’t necessarily preserve time and space complexity (try interpreting an impure language in a pure one).
Yeah, alright, thanks for that clarification. I didn’t realize I was thinking about it in terms of “Java/Python/C/etc. running on some traditional computer”.
Agreed that interpretation is quite prone to overhead and delays.
Any suggestions for finding a larger project to work on to advance the later skills, if one is mostly doing self-study? (I’m an EE student dabbling in various languages, and don’t feel super-comfortable working with large projects yet, though I’ve had some experience with C++-specific stuff.)
Some projects become large because besides the central problem or a set of central problems there is also a lot of infrastructure: user interface, data serialization, export and import, etc.
Here is an example of a school project:
“Find the cheapest path between points A and B in a weighed graph.”
Here is how the same problem would look in a real life:
“Create a web application for transporting cargo. Many companies provide transport between specified cities. The customer needs to move their cargo from place A to place B. The application finds and displays the cheapest path on Google Maps.
User can select starting and ending position by clicking the icons of stations on Google Maps, or by selecting from the pull-down input. (The first input displays a list of countries with at least one station, on the selection the second input is shown with a list of stations in given country.) User provides the total weight of the cargo, and selects checkboxes if the cargo has some special properties (e.g. fragile, radioactive, biohazard). Then user clicks on the Search button.
The shortest path is computed and displayed visually on the Google Maps. On the side of the screen the list of path segments is displayed: the length of each segment, the price of transport through this segment, and the company which provides the transport. Then the total length and total price. By clicking a button the user can export the list to a PDF file.
Administrator can log in the system using their username and password. Administrator can edit the list of stations: name and GPS coordinates in the station. The GPS coordinates can be provided as numbers, or by clicking or dragging the station icon on the Google Maps. The data are stored in a database. The list of stations can be exported to an Excel file, or imported from the Excel file.
There is more than one administrator, each one has their own username and password. Each administrator editing action must be saved to a log file, so if one of them intentionally destroys some data, it can be found who did it and when. One or more administrators can be meta-administrators with ability to create or remove administrators, or edit their data (username, real name, phone contact,...) or change their password. These data (except for the password) can be also exported to Excel.
Administrator can also edit the list of track segments consisting of: starting station, ending station, company, maximum weight, price per unit weight, and whether cargo with special properties (fragile, biohazard...) can be transported there. There can be more than segment between two stations for the same company (e.g. a cheaper option for normal cargo, and a more expensive or more weight-limited option for fragile cargo), however if there are two options for the same company where one is strictly better than the other (not more expensive and not more limited), this is clearly a mistake and should be displayed. The list of segments can also be exported to Excel and imported back. The export has an option of exporting everything to a single Excel file, or to a separate Excel file for each company.
By the way, the lists of stations and segments the administrators edit are displayed in a table, which has 20 rows per page, can be sorted by any columns, and filtered by various criteria.”
What open source software do you like? I think the best would be to pick a small software with 1-5 core developers.
Go to the mailinglist of the project and say that you want to help. Describe your present ability and ask for suggestion about how you could best contribute code to the software.
A lot of open source projects are happy to welcome new developers. Senior programmers at the project will review your code and tell you if it’s bad.
In case some open source project isn’t happy to welcome you, move to the next project.
A book that greatly improved my code was Clean Code by Robert C. Martin. It helped me understand things such as when code comments are appropriate and how to split code into well-factored functions. The book’s main flaw is that it’s sometimes hard to tell which of its advice is Java-specific and which is widely applicable. But I definitely still recommend it.
The author wrote another book, The Clean Coder, which is also about improving as a programmer. It’s not about coding well – it’s “a code of conduct for professional programmers”, and talks about things like when to say “no” to your boss, how to make a commitment, and how to estimate time for tasks. It was not as good as Clean Code, but it was helpful.
It seems to me that many of the people we see as great programmers are those who made their mark on a particular field of programming. So my answer would be, if you’re already an okay programmer (can get hired at Google or a hedge fund), you could pick a subfield that intensely interests you, and just dive as deep as you can.
The reason most people don’t do that is most jobs have a mismatch between what’s interesting to you and what’s useful to the employer. It’s worth trying to minimize that mismatch and get encouragement from your employer somehow, though I have no idea how, it seems to mostly depend on luck.
A lot of these links are about how to get started coding. I am already a good programmer, maybe a damn good programmer. But I know there’s a level above mine, and probably several. How do I get to the next level? What does the next level look like? Are there any resources that talk about how to become a great programmer?
My programming “achievements” were like this:
Learning the commands of my first programming language.
Learning the concepts of “if-when-else” and “while”.
Using functions to manage programs with more than dozen lines.
Using multiple files to manage programs with more than dozen functions.
Realizing the importance of writing good documentation.
Cooperating with other people on the same project.
Using directories and projects to manage programs with more than dozen files.
Realizing the importance of reading the specification.
Learning design patterns.
Realizing the importance of using the right tools for the job.
Learning refactoring.
Testing my code.
Seeing my code as a web of functionality, instead of a list of text files.
Learning a few new programming languages, and using parts of their style in other languages.
Designing architecture of a large project.
Leading other people in a project. (not completed yet)
Keeping focus on Getting Stuff Done. (not completed yet)
Each one of them could be a topic for a separate discussion. Some of them have this zen-like aspect that you first learn about a concept (e.g. object-oriented programming) and you use it everywhere; then at some moment you start to understand where it provides value and where it does not, and then you use it less. Stuff that once felt like the essence of programming gradually becomes just another tool in the box, to be used or replaced when necessary: you don’t have to use this specific library, this specific programming language, or this specific programming style.
The “social” skills (cooperating, leading), are not programming per se, but they will force you to use the other skills more carefully, because every mistake will hurt you tenfold.
Things that helped me:
Learning about formal languages at university. I would probably never learn it alone, because it seems so abstract. Most self-taught programmers don’t learn this. But for a certain kind of problems (text processing: parsing data files, evaluating expressions, interpreting or compiling a language) it gives you the magical skill of looking at the problem and almost instantly seeing that “this problem belongs to this category of problems, and these are the standard tools to solve it; the tools for a different category would fail because so and so”.
Learning different programming languages. The new languages introduce new concepts, but sometimes they show how the concepts which seemed essential in other languages can be avoided or done differently. -- I don’t need line numbers outside of old versions of Basic. I don’t have to make data type a part of the variable’s name if I use static typing. The data types are not only for the compiler to determine the variable size in bits, but they can describe the meaning of the value. I don’t have to use complicated variable names, if the scope of the variable is limited. In Java I use interfaces to describe what the class does, and extend classes to specify how. JavaScript and Lua allow object-oriented programming, and they don’t even have classes. A function is just another type of value, and it can be stored in a variable. Functional languages do not even allow changing the value of a variable, and you still can do what you need. You can write a program to generate a program. You can make your own programming language. All Turing-complete languages are equivalent, so at the end what really matters is the convenience of use.
Reading the original documentation, as soon as you are able to understand it. For information about HTML, read W3C specifications, and avoid w3schools. For information about Java, read Java Language Specification and tutorials made by Sun. Most online tutorials are written by people who don’t really understand the topic, they just learned it yesterday, and today they are trying to make some fame and adsense money from sharing their confused thoughts. (Especially everything related to PHP. Also PHP itself.) If most programmers are on the level zero, there will be many level-one gurus, and level-two system architects.
These kinds of recommendations are good, but not exactly what I was looking for, probably because they are a bit too high-level. Let me give you an example of the types of things I think have made me an incrementally better programmer recently:
Using a scripting language (Jython or Matlab) in combination with a compiled language (Java) to get the best of both approaches. One-off, adhoc analyses or jobs can be quickly developed in the scripting language, and then either thrown away or migrated to the compiled language if they prove to be useful. The ability of a tool like Jython or Matlab to script Java objects means that you can reuse your highly polished object logic in the scripting language.
Enforcing a “no-cycles” rule in my list of object and package dependencies. A full build of my code compiles package-by-package, so that if package A is ordered before package B in the list, package A cannot refer to package B. This is a good straitjacket to put yourself in, but I actually take it a step further and require that there cannot be circular object dependencies within a package.
A “smart” fast compilation script that checks if a source file has been modified and then recompiles just that file. This is actually kind of fast and loose in the sense that it can introduce bugs if you’re not careful.
Extensive use of assertions. Assertions actually serve two purposes—the obvious purpose of producing a “fail-fast” effect so that the code breaks immediately and for a clearly specified reason when the assertion fails. But they also serve for self-documentation. For example, say you are using a method that takes two arrays, one of size NxM and the other of size NxP. This introduces the potential for bugs if the array sizes don’t line up and also confusion if the caller can’t figure out whether s/he needs to pass an array or its transpose. Putting in the appropriate assertion both prevents confusing error messages but also indicates to the reader what the correct array sizes are.
Figuring out how to rely on the compiler more to catch potential errors at compile time. By writing code in a certain way, you can be more confident that IF there is an error, the compiler will catch it. One principle here is to use methods with mixed signatures—it’s better to have mymeth(String, int, boolean) than mymeth(String, String, String) because in the latter case the compiler won’t be able to catch it when you pass the arguments in the wrong order. Using enums is also a good idea.
Use of AutoHotKey to remap common commands to keyboard shortcuts that are easier on the fingers. For example, I remap cut and paste operations to the function keys, because I don’t like stretching my left pinky finger all the way out there to hit the control key.
Some things I need to get better at:
I need to know more about Unix. I have been procrastinating on taking the plunge and switching over to Linux for personal use.
Overall I need to have a more efficient computing environment—not just the programming language but the full ecosystem of tools: editor, shell, scripting language, keyboard, etc. (Aha, I just realized that I want my shell to produce sounds or music to supplement the text output so I can actually hear it if a program is behaving improperly).
I need to get better at building modular parameterized components and reusing them to build more complex applications. The Unix pipe-output-to-input is the model here, but it doesn’t do all the things I need it do. I can imagine a visual “wiring diagram” tool here (maybe similar to SpaceChem) that allows the user to hook up programs to each other, using basically the same piping idea, but in a more flexible way.
I should be able to make better estimates both for how long various process will take and how long they should take if my code were perfectly efficient (i.e. how close am I getting to the actual physical limitations of the hardware).
I should get better at using code analysis tools to detect errors. One thing that constantly annoys me is variable shadowing, and that should be possible to detect automatically ( I know some IDEs do this. I have mixed feelings about IDEs).
I am a big fan of IDEs, because they can remove a lot of trivial (or not so trivial) inconveniences.
I point a mouse cursor at any variable / function / class, and a documentation is displayed; if I press Ctrl and click, the definition is opened. What is the alternative: Remembering everything?
I often rename my variables / functions / classes, because I believe that the name should reflect the meaning as closely as possible, but sometimes when I finish writing something, I realize the meaning is slightly different than I originally thought. IDE replaces all instances of the given thing, but does not touch other things with the same name (e.g. a local variable in a different function, or a method of a different class). What is the alternative: Always thinking hard about the name? Leaving the old name even when it feels wrong? Check carefully whether only the correct words are being replaced?
Generally, when I work with a good IDE, I am not just editing a set of text files, but I feel like I am working with the generated classes and functions directly. Because it is so responsive, it feels more real. When I work without the IDE (or with a bad IDE), it feels very clumsy. For example, I can type “my_obj.my_func()” on the keyboard, but I don’t get an immediate response whether an object “my_obj” exists, whether it has a function “my_func”, whether the function has zero parameters. The IDE gives me this feedback all the time, it feels so natural, and I become tense without it. Sure, I can get the feedback later, from the compiler. But that’s like a difference between walking with open eyes, and walking with closed eyes and shortly looking around once in a minute. I can still successfully navigate to my goal, it just takes a heavy tax on my attention.
My favourite IDE is Eclipse, for Java. In settings it has a long list of things some people consider bad programming style, and you can select which of them will be underlined in the source code as warnings. Just reading the whole list is interesting. Once I tried to turn on all of them and then improve my program to fully pass the test. (Then I turned off one setting. It required localizing all the strings in code; that would be an overkill.) I learned some interesting things from that. But this could be achieved also by using an external tool, such as FindBugs or PMD.
How do you avoid circular dependencies between e.g. “a node is a branch or a leaf” and “a branch contains two nodes”?
I agree with the other things (with the sidenote that some IDEs give you smart compilation and keyboard shortcuts automatically). The idea of an acoustic feedback sounds interesting!
If you want to develop your *nix skills, switching to Linux for personal use will not be as much help as you think. The most sure-fire way of picking up Linux chops is having to work with a core installation you can only access through the command line.
This is all good, but also just stuff that gets you from a neophyte to a competent programmer. What about the part where you want to get from the competent programmer level to the John Carmack, Peter Norvig and Oleg Kiselyov level?
You could ask them. But someone got to that level first, how did they do that?
Let’s suppose my goal is to become so cool that I could code StarCraft 3 during a weekend… without all the textures and levels and music and movies; just with some sample data, so my minions can later provide the rest. This would make me rather happy. :D
I could just spend one weekend doing my best, which obviously would not be enough. Then I could reflect on what was wrong. What was really slowing me down. I could try to research a solution for that (there is always a high prior probability that someone else already did it), or try to solve the problem myself. If I found I was missing some specific skill, I would focus on improving that skill.
The next test weekend, I could start again from the very beginning—more precisely, I would not reuse the specific code that I wrote the previous weekend; however, if in meantime I have prepared some useful library for myself, I would use that. The idea is that I am not unnecessarily handicapping myself; I am just assuming that what I did previously was wrong, so I am not going to build on my mistakes, but to do it right. Also, by always starting again I could get some feedback on whether this weekend I was really more effective than the previous one.
Well, any Turing complete language can implement a sort, but not every language can implement a sort in O(n log n) time, or a sort that uses O(log n) additional memory. Sorry, just being nitpicky.
True, though any turing-complete language can definitely, provably implement a sort that uses O(n log n) + k time or uses O(log n) + k additional memory (or straight-up all of them can do O(log n) memory if they have hard drive write access and OS auth to run other programs). “k” here is the amount of time it takes for this program to write and compile a compiler for some other, more efficient language, and then write the algorithm in that language, compile, and then run that.
At the extreme, the program could be an AI specialized in figuring out how to code the most efficient sorting algorithm given certain hardware specs, then figure out the most efficient language to write that in, then write it, then save it, then run it and delete itself.
Obviously, this is far, far from being convenient or efficient.
My comment viewed a Turing complete language as a sort of self-contained mathematical thing, which doesn’t necessarily have access to the operation “ask the OS to run this sequence of x86 instructions”. When people talk about Turing equivalence, that’s typically the meaning they use.
Interpreting one language in another is okay, but interpretation doesn’t necessarily preserve time and space complexity (try interpreting an impure language in a pure one).
Yeah, alright, thanks for that clarification. I didn’t realize I was thinking about it in terms of “Java/Python/C/etc. running on some traditional computer”.
Agreed that interpretation is quite prone to overhead and delays.
Any suggestions for finding a larger project to work on to advance the later skills, if one is mostly doing self-study? (I’m an EE student dabbling in various languages, and don’t feel super-comfortable working with large projects yet, though I’ve had some experience with C++-specific stuff.)
Some projects become large because besides the central problem or a set of central problems there is also a lot of infrastructure: user interface, data serialization, export and import, etc.
Here is an example of a school project:
“Find the cheapest path between points A and B in a weighed graph.”
Here is how the same problem would look in a real life:
“Create a web application for transporting cargo. Many companies provide transport between specified cities. The customer needs to move their cargo from place A to place B. The application finds and displays the cheapest path on Google Maps.
User can select starting and ending position by clicking the icons of stations on Google Maps, or by selecting from the pull-down input. (The first input displays a list of countries with at least one station, on the selection the second input is shown with a list of stations in given country.) User provides the total weight of the cargo, and selects checkboxes if the cargo has some special properties (e.g. fragile, radioactive, biohazard). Then user clicks on the Search button.
The shortest path is computed and displayed visually on the Google Maps. On the side of the screen the list of path segments is displayed: the length of each segment, the price of transport through this segment, and the company which provides the transport. Then the total length and total price. By clicking a button the user can export the list to a PDF file.
Administrator can log in the system using their username and password. Administrator can edit the list of stations: name and GPS coordinates in the station. The GPS coordinates can be provided as numbers, or by clicking or dragging the station icon on the Google Maps. The data are stored in a database. The list of stations can be exported to an Excel file, or imported from the Excel file.
There is more than one administrator, each one has their own username and password. Each administrator editing action must be saved to a log file, so if one of them intentionally destroys some data, it can be found who did it and when. One or more administrators can be meta-administrators with ability to create or remove administrators, or edit their data (username, real name, phone contact,...) or change their password. These data (except for the password) can be also exported to Excel.
Administrator can also edit the list of track segments consisting of: starting station, ending station, company, maximum weight, price per unit weight, and whether cargo with special properties (fragile, biohazard...) can be transported there. There can be more than segment between two stations for the same company (e.g. a cheaper option for normal cargo, and a more expensive or more weight-limited option for fragile cargo), however if there are two options for the same company where one is strictly better than the other (not more expensive and not more limited), this is clearly a mistake and should be displayed. The list of segments can also be exported to Excel and imported back. The export has an option of exporting everything to a single Excel file, or to a separate Excel file for each company.
By the way, the lists of stations and segments the administrators edit are displayed in a table, which has 20 rows per page, can be sorted by any columns, and filtered by various criteria.”
What open source software do you like? I think the best would be to pick a small software with 1-5 core developers.
Go to the mailinglist of the project and say that you want to help. Describe your present ability and ask for suggestion about how you could best contribute code to the software.
A lot of open source projects are happy to welcome new developers. Senior programmers at the project will review your code and tell you if it’s bad.
In case some open source project isn’t happy to welcome you, move to the next project.
A book that greatly improved my code was Clean Code by Robert C. Martin. It helped me understand things such as when code comments are appropriate and how to split code into well-factored functions. The book’s main flaw is that it’s sometimes hard to tell which of its advice is Java-specific and which is widely applicable. But I definitely still recommend it.
The author wrote another book, The Clean Coder, which is also about improving as a programmer. It’s not about coding well – it’s “a code of conduct for professional programmers”, and talks about things like when to say “no” to your boss, how to make a commitment, and how to estimate time for tasks. It was not as good as Clean Code, but it was helpful.
You can easily download ebooks of these from Google searches: Clean Code, The Clean Coder.
It seems to me that many of the people we see as great programmers are those who made their mark on a particular field of programming. So my answer would be, if you’re already an okay programmer (can get hired at Google or a hedge fund), you could pick a subfield that intensely interests you, and just dive as deep as you can.
The reason most people don’t do that is most jobs have a mismatch between what’s interesting to you and what’s useful to the employer. It’s worth trying to minimize that mismatch and get encouragement from your employer somehow, though I have no idea how, it seems to mostly depend on luck.
There’s http://norvig.com/21-days.html with provides a bunch of suggestions.
Otherwise getting better at programming is like getting better at anything. You need to spot patterns of suboptimal behavior.
Do code reviews with other people. Talk about whether the code is optimal and how it can be improved.
Paul Graham’s writings on programming and learning Haskell leveled me up. Although i suspect you are already at that level.