Ask HN: What habits make a programmer great?
So what are the habits I should cultivate to be a great programmer or even a good one? What are the bad habits that I should drop?
So what are the habits I should cultivate to be a great programmer or even a good one? What are the bad habits that I should drop?
Some that occur frequently are:
* Take care of yourself. Get enough sleep, exercise and healthy food. Have hobbies.
* Constantly learn new stuff
* Practice communication skills. Building stuff fast and well doesn't help if you're building the wrong thing, and you need communication skills to prevent that
* Think about the context that your program will run in (related to the reason above)
* Practice empathy
Any tips on how to do this? I don't often feel things for myself and it's even rarer to experience empathy at a level I can detect. I meditate to try to better understand and learn to detect my feelings, but haven't made much progress yet (I use Headspace).
Its hard to empathise if your thoughts are elsewhere. When a situation requires/deserves empathy then be aware (mindful, if you like) of the locus of your thoughts and, when they wander, direct them back to the subject. Your meditation practice will definitely help there.
Consciously recognising when your empathy is needed is the hard part. All I can suggest is to try to recognise and avoid habitual distraction.
Everybody struggles with this. I find it hugely embarrassing. Don't bother calling people out for making mistakes, if they're any good, they know they've made a mistake. Instead, give advice about how you avoid those kinds of errors. We've all been there. It sucks. Instead offer up some tricks or techniques for avoiding that kind of problem in the future. If it's really bad, a war story about how you really messed up bad can be calming.
The gist is, your coworker is probably feeling a lot of emotions. We've all felt those emotions, and it's going to be ok. Later, we'll have a post mortem and find a way so nobody can ever have that problem again (or make it harder). It sucks coworker had to be the one to break things in that way, but coworker is helping ever other person to come after them. Somebody was going to do that eventually, coworker just got unlucky.
Backed by science! https://www.scientificamerican.com/article/novel-finding-rea... https://www.theguardian.com/books/booksblog/2013/oct/08/lite... https://www.washingtonpost.com/news/speaking-of-science/wp/2... https://www.psychologytoday.com/blog/the-athletes-way/201412...
I've been confronted with this question a couple of times even before I read the articles linked above and I always answered the same. Always felt like it's such an "obvious" answer since reading fiction puts you in the perspective of another person/character, so it's good empathy exercise. My personal experience confirms this as well, that when I want to shift my perspective to that of another, reading fiction helps.
(Emphasis on "personal" as, in this use case, YMMV.)
Two very different books but, Between the World and Me, and How to Get Filthy Rich in Rising Asia both made me think in ways I cant quite describe.
They can't speak. You have to empathize with them to have any relationship with them. In social situations you'll end up reading body language and worrying about other's feelings without even thinking about it due to pet practice.
Note: I don't have empathy for myself very well, but my own behavior can tread bizarrely enough that I am forced to examine my own behavior in a way that can be explained to others reasonably. If you can explain others' behavior in this way that isn't condescending towards them, that takes all aspects into their behavior into account, you will come off as compassionate and empathetic regardless of how you feel in the situation. At least this has been my experience.
Raise kids. No joke. They can do some pretty stupid things, and keeping them out of danger and helping them grow has actually helped me understand and empathize with my team quite a bit.
Be generous with your life (from small things like hosting guests in your home, to traveling to help people survive and thrive in other countries). When you see what others are going through, you'll probably have a gut reaction. You should probably trust your gut.
Read books on leadership. It helps to learn how other good leaders coped with similar circumstances. -- and yeah, I just called you a good leader without meeting you. Just asking this question and being introspective indicates you're on the path to being a good leader.
Doing all the other self-care that OP mentioned is a good way to start moving in that direction. Be patient and kind to yourself. Once you've learned that, you actually start developing and being able to feel that way about others. It sounds a little hippie dippie, but once you have patience and you're at peace with yourself, you're much better at being able to accept the faults of others.
Especially seems that a lot of devs forget about the first point.
In my experience, when I've started doing gym & swimming I became to feel less "burned out" as well as my self-esteem improved :-)
If you try to work on a complex algorithm with little sleep, you tend to throw a wrench into it.
I often encounter situations where a day or two were spent creating a mess of classes and abstractions, yet the actual logic to solve the problem still hasn't materialised. A defense about "code quality" or "not wanting to write spaghetti code" is often made.
My recommendations for a problem you don't have a clear solution in mind for:
1) Hack some pseudo-code spaghetti together in a blank file until you think "you got it"
2) Write some theoretical test scenarios in another blank file (given state, steps, outcome) to verify that it's actually "solved". Discuss with a team member if possible.
3) then write out those functions from 1) inside the existing codebase
4) verify stuff is working
5) only then do abstractions / splitting up into multiple files
For a problem where the solution is already existing, but the implementation lacking (e.g. a refactoring)
1) design the new code (data structures, interfaces)
2) always propose to the team - no ninja-architecture/refactors
3) ensure the solution can be tested, document what should be tested
4) execute on the implementation
YMMV
To convert from a prototype to an end-product, you need to do the other steps.
But:
If you know multiple programming languages. Sometimes adjust for the toolset. Eg. Python or NodeJS for crawling websites. I always abstract it with an api. For eg. Try take a screenshot of a website in c# ( my most proficient language).
SOME tools do get you much faster to the end result with more options. Just make sure you tackle that problem with that programming language and try to abstract it away.
Edit: My solution for website as a screenshot, a c# wrapper for a nodejs api
The API in Nuget ( dot nets package manager): https://www.nuget.org/packages/WebsiteAsImageWebService.Api/
Proper understanding of the problem is extremely important. Great advice.
There is a lot to be gained by going along with the dominant groupthink on a topic, and there is a lot of risk involved in declining to do so. This is especially true as the groupthought picks up steam and gains powerful backers, who will be offended that little-old-you would dare to contradict someone of their high status.
The likelihood that your successes over the conventional/trendy method will be undeniably obvious is very low, especially when you consider that as larger interests and personalities invest in the groupthought, their PR machines will be working to discredit/counteract those who stand to imperil their investment. You will probably not get the punchy ending that you'd need to justify the burn you initiated by going your own way.
You could try to argue that the rest of the team is just trying to follow the zeitgeist instead of thinking about how to generate objective value, but this will hurt much more than just smiling and using the "Tech Flavor of the Week" on the project.
Team cohesion is more important for large-scale productivity than technical implementation details. It's easier to work around a buggy framework than it is to get people to cooperate and release their grudges.
If you want to be a "great programmer" in the sense that you have maximal self-satisfaction, then yeah, you should use whatever you think is best.
If you want to be a "great programmer" in the sense that you're a hot commodity on the market with a strong network full of people who want to give you money, you must recognize that your field of operation is not really computer code, but the delicate egos of the humans around you.
---
Along a less social track: the bigger the technology gets, the more likely that its kinks will get worked out and that it or something based on it will become a driving force in something that is objectively useful/valuable down the road, at which time having the investment in the platform makes it easier to adopt the better tech from both a technical (increased familiarity with tech-specific syntax and concepts) and personal perspective (don't have years of resistance that you've brainwashed into yourself, + accompanying reputation).
JavaScript is a good example of a technology that has been difficult to justify at a technical level in any case where it wasn't mandatory up until very recently. However, its widespread faddiness is now starting to cause actually useful new things to be JavaScript-first or JavaScript-based, even if they're doing that just so they can ride the hype wave themselves.
My experience has taught me the exact opposite: no amount of Google Docs or whiteboarding meetings will tell you what the real problems are, you're only going to find them when you start implementing.
I got burned on my last project: we spent several weeks mostly talking and writing (English) about problems that turned out to be trivial, and got totally blindsided by problems that were not detectable until we actually connected to the firehose of incoming data (it's a streaming/analytical system) and then verified our work. There were lots of subtleties in the way a small portion of messages could be related over days and weeks. Nothing we would have been able to forsee with unit tests or manual inspection. We had to actually write the program to find out what would be hard about it.
When you hear them say: "I need a modern site", don't start until you're clear why they want it. For example "My customers told me my site doesn't look very trustworthy" will lead to a different solution than "My site is too slow" or "My site doesn't work on mobile devices".
Once you know the customer's why, you are also better able to make decisions like "It's okay to lose 1% of the data in case of failure in order to have a simpler system", or "We only look at the results once a day anyway, so using batching is acceptable".
1. Start small, then extend.
2. Change one thing at a time.
3. Add logging and error handling early.
4. All new lines must be executed at least once.
5. Test the parts before the whole.
6. Fix the known errors, then see what’s left.
Taken from here: https://henrikwarne.com/2015/04/16/lessons-learned-in-softwa...
1. If at all possible start from something existing. It is entirely possible by the time you are done nothing remains of the existing. That's fine. To me, it's easier to tweak existing code than fill in an empty editor window. To some, an empty editor window is all opportunity, to me, it's analysis paralysis.
2. Always be ready to throw everything away. You perhaps will save a few choice lines but be ready for your first, sometimes even the second solution to suck badly. This is fine. Putting in more time to have an easier to maintain solution is always useful.
3. To continue from there, easier to maintain code is king. Unless you are writing something extremely time critical do not try to be clever. A little slower is okay (and yes, I am in the performance consultancy business) if it significantly decreases the maintenance burden. Clever hacks belong to toy projects and blog posts. The next person who maintains it will be stupid to the code -- even if it's yourself. That clever hack is now a nightmare to untangle. In short: always code under the assumption that you will need to understand this when the emergency phone kicks you out of bed after two hours of sleep in the middle of the night. The CTO of Cloudflare was woken to the news of Cloudbleed at 1:26am.
What if you write a function in Go that's littered with the usual
if err != nil {
return err
}
and the error that's being propagated is hard to reproduce, e.g. a filesystem error? I never cover those "return err" in actual programs.Creating tests for some of these cases would involve mocking things out, and then you have to make assumptions that may not hold anyway. That's why I like to see it execute in the real environment at least once.
Yes, a lot of things like that are possible. I remember in one client-server project I worked on, we unplugged the network cable from one PC (while the program was communicating between client and server), to see if we got the correct error message that we had written for that case. And did other stuff like that.
This was done in a project I handled, for the World Bank. I had a team of 9 motivated though young developers (first project for most of them). Near the end, before we sent the software to the client, a colleague was assigned to test the software - testing by a member external to the team, a slightly senior guy, ex-CITIL (a Citi IT subsidiary which had more mature software processes than we did then), though of course we did test the software ourselves a lot, first. I remember what happened:
We prepared the machines and software for the test. Called him over.
He said: I am going to sit down and destroy your software.
We said: Go ahead, please try.
And he tried to. But could not. He only found a few minor cosmetic defects.
Getting up after a few hours of rigorous testing, he said something like - I am happy with your work.
1. Return something meaningful, not the bare error you received above.
2. If you do nothing but decorate the error, ignore coverage. Having decorated the error helps debug the full system when the error occurs.
3. If your error handling is more complex (remove temporary files, close handler, etc.), you might want to factor the cleanup into its own function and test it there.
Finally, your code is not really "littered." If you had exceptions, there would be no trace of the possible errors that might occur on the production system. Your coverage will be higher, but when the software will blow up in production, it will not matter then least.
- More communicating, less coding. This is extremely important in teams and large organisations. Communicate to make sure nobody does double work. Communicate to have your ideas and opinions heard. Communicate to avoid doing pointless work. The list goes on. Communicate with your peers, your boss, your customers.
- Have healthy habits. Eat well, sleep well, exercise. When you're young you can pull off all nighters and eating pizza's all week. As you get older, you cannot.
- Be reliable. When you say you're going to do something, do it. Write reliable, well-tested code that works.
- Fail. Make mistakes. And learn from them. Don't be afraid to take on a challenge. You cannot expect to be great without having made mistakes. You'll make them once and hopefully never again.
- Follow up. When people send you e-mails and messages. Answer as fast as you can. Things move a whole lot more quickly when people don't wait on each other.
- Be on time. Nobody likes people who are late.
- Always learn. Try new things. If you don't like them, then at least you tried and learned something new. Keep exploring and reading.
"Value is loosely defined"
This is a really worthwhile thing to think about - not only creating value, but levering it up.
If you spend the time to work/find something out, demonstrate it to others. If you change someone else's code for the better, explain why.
Minimise the cost of organisational communication - operate transparently. Pro-actively communicate your status/progress and respond quickly and clearly to requests for such.
Boost others. Communicate success upward in terms of the team - even if you did it.
"Researchey" green-field development for data-science-like problems:
1. If it can be done manually first, do it manually. You'll gain an intuition for how you might approach it.
2. Collect examples. Start with a spreadsheet of data that highlights the data you have available.
3. Make it work for one case before you make it work for all cases.
4. Build debugging output into your algorithm itself. You should be able to dump the intermediate results of each step and inspect them manually with a text editor or web browser.
5. Don't bother with unit tests - they're useless until you can define what correct behavior is, and when you're doing this sort of programming, by definition you can't.
Maintenance programming for a large, unfamiliar codebase:
1. Take a look at filesizes. The biggest files usually contain the meat of the program, or at least a dispatcher that points to the meat of the program. main.cc is usually tiny and useless for finding your way around.
2. Single-step through the program with a debugger, starting at the main dispatch loop. You'll learn a lot about control flow.
3. Look for data structures, particularly ones that are passed into many functions as parameters. Most programs have a small set of key data structures; find them and orienting yourself to the rest becomes much easier.
4. Write unit tests. They're the best way to confirm that your understanding of the code is actually how the code works.
5. Remove code and see what breaks. (Don't check it in though!)
Performance work:
0. Don't, unless you've built it and it's too slow for users. Have performance targets for how much you need to improve, and stop when you hit them.
1. Before all else (even profiling!), build a set of benchmarks representing typical real-world use. Don't let your performance regress unless you're very certain you're stuck at a local maxima and there's a better global solution just around the corner. (And if that's the case, tag your branch in the VCS so you can back out your changes if you're wrong.)
2. Many performance bottlenecks are at the intersection between systems. Collect timing stats in any RPC framework, and have some way of propagating & visualizing the time spent for a request to make its way through each server, as well as which parts of the request happen in parallel and where the critical path is.
3. Profile.
4. Oftentimes you can get big initial wins by avoiding unnecessary work. Cache your biggest computations, and lazily evaluate things that are usually not needed.
5. Don't ignore constant factors. Sometimes an algorithm with asymptotically worse performance will perform better in practice because it has much better cache locality. You can identify opportunities for this in the functions that are called a lot.
6. When you've got a flat profile, there are often still very significant gains that can be obtained through changing your data structures. Pay attention to memory use; often shrinking memory requirements speeds up the system significantly through less cache pressure. Pay attention to locality, and put commonly-used data together. If your language allows it (shame on you, Java), eliminate pointer-chasing in favor of value containment.
General code hygiene:
1. Don't build speculatively. Make sure there's a customer for every feature you put in.
2. Control your dependencies carefully. That library you pulled in for one utility function may have helped you save an hour implementing the utility function, but it adds many more places where things can break - deployment, versioning, security, logging, unexpected process deaths.
3. When developing for yourself or a small team, let problems accumulate and fix them all at once (or throw out the codebase and start anew). When developing for a large team, never let problems accumulate; the codebase should always be in a state where a new developer could look at it and say "I know what this does and how to change it." This is a consequence of the reader:writer ratio - startup code is written a lot more than it is read and so readability matters little, but mature code is read much more than it is written. (Switching to the latter culture when you need to develop like the former to get users & funding & stay alive is left as an exercise for the reader.)
It's helped that it's really been 12 (well, 13+change) years of experience, rather than one year repeated 12 times. Each year has brought something new and different that's just out of my comfort zone.
> Don't ignore constant factors. Sometimes an algorithm with asymptotically worse performance will perform better in practice because it has much better cache locality.
Forget the cache, sometimes they're just plain faster (edit in response to comment: I mean faster for your use case). I've e.g. found that convolutions can be much faster with the naive algorithm than with an FFT in a pretty decent set of cases. (Edit: To be specific, these cases necessarily only occur for "sufficiently small" vectors, but it turned out that was a larger size than I expected.) Caching doesn't necessarily explain it I think, it can just simply be extra computation that doesn't end up paying off.
> sometimes they're just plain faster
Not faster for sufficiently large N (by definition).
But your general point is correct.
I've best seen this expressed in Rob Pike's 5 Rules of Programming [0], Rule 3:
Rule 3. Fancy algorithms are slow when n is small, and n is usually small. Fancy algorithms have big constants. Until you know that n is frequently going to be big, don't get fancy.
True, but supposedly researchers keep publishing algorithms with lower complexity that will be faster only if N is, like 10^30 or so.
Or so Sedgwick keeps telling us.
This is my #1 pet peeve with GitHub. When I first look at an unfamiliar repo, I want to get a sense of what the code is about and what it looks like. The way I do that with a local project is by looking at the largest files first. But GitHub loves their clean uncluttered interface so much, they won't show me the file sizes!
Check out Octotree if you're using Chrome. No file sizes still, but I've found that when you just want to quickly explore some potential new source this beats having to clone the repo first.
I think this Chrome extension called "GitHub Repository Size" might be exactly what you are looking for
This is true not just for data science but when trying to solve any numerical problem. Using a spreadsheet (or a R / Python notebook) to implement the algorithm and getting some results has helped me in the past to really understand the problem and avoid dead ends.
For example, when building a FX pricing system, I was able to use a spreadsheet to describe how the pricing algorithm would work and explain it to the traders (the end users). We could tweak the calculations and make sure things were clear to all before implementing and deploying the algorithm.
Great advice!
I work with a lot of traders. One antipattern I noticed is that when there's a problem with the data, they'll do all sorts of permutations and aggregations and then scratch their chins and ponder about it for hours.
Go to the fucking source and find an example of the problem! Read it line by line, usually it will be obvious what happened.
Corollary: Don't assume your data is correct, most outliers ina large data set are problems with the data itself. Build a few columns that serve as sanity checks. One good example is a column that shows the distance between this sequence number and the last, anything >1 is a dropped message.
6. Use assertions for defining your expectations at each stage of the algorithm - they will make the debugging much more easier
On HN, I often check specific commenters activity, or new comments in a thread that can be days-old, because I often find hidden gems. A link to more elaboration would definitely count as such. Perhaps an audience of even just a dozen or so people like me might be worth it.
EDIT: Coincidentally (I swear), there's exactly a dozen of comments that positively engage with your comment!
I reformatted this in a Google Doc, if anybody wants: https://docs.google.com/document/d/1Pix3-l3Qz1aLOuxoiiP1PTV6...
Take error handling really seriously. A program that can gracefully reject input with a detailed error message is far better than one that crashes mysteriously
That attitude hurts everyone who has to support what you write.
edit: Reformatted as a habit "Make sure whatever you write can be supported without unnecessary headaches."
Assertions, however, are great. If you can force the program to throw that NPE closer to the point where it actually illegitimately became null, the debugging session becomes much shorter. Null-safety in the type system (like with most modern languages: Swift, Haskell, Kotlin, Scala, Rust, etc.) is even better.
And: Using a different language is always a great idea, but often not possible.
Code should tolerate all sorts of bad inputs. Code should produce pristine outputs.
Just like being a model member of society
Googled and found it:
https://en.wikipedia.org/wiki/Robustness_principle
https://en.wikipedia.org/wiki/Jon_Postel
"In his lifetime he was known as the "god[2] of the Internet" for his comprehensive influence on the medium."
1. Re-structure your logic so the error cannot happen
2. If you can't do 1, recover from the error silently and continue on with the program
3. If you can't do 2, handle the error gracefully and notify the user of what state is changed, letting them choose whether or not to continue
4. If you can't do 3, inform the user of what happened and ideally provide the user corrective action they can take, then exit cleanly with an error code
5. If you can't do 4, exit cleanly with as descriptive of an error code as you can
6. If you can't do 5, you're probably faced with crashing or exiting with some unhandled exception. This is a bug that should never go into production.
Always be looking for opportunities to move your code up that hierarchy. Moving every 6 to 5 is my personal bar for barely acceptable quality. 4->3 is usually a big win (basically anything that prevents the program from exiting).
I think that defensive programming is the worst way of dealing with errors. You are now silently diverging from your business requirements by making up data.
To give "urge" more meaning: These days I get a noticeable weird feeling in my gut if I'm working in a environment where there are too many unknowns.
That's fear for me. Always a chance I'll knock something important over...
further, try to create an environment where others (particularly others who are less powerful) feel comfortable voicing their concerns and are secure enough to state when they don't know or don't understand something.
e.g. if people are worried they are going to be fired or ridiculed in a group setting for not knowing a thing then it would be unreasonable to expect them to say "i don't know".
Oh and also, NEVER make any assumptions about how people will use your software
But what you don't want to do is reinvent the wheel just because you can. Don't write your own crypto, and use whatever FOSS software (with a license approved by your employer) and existing solutions that you can, unless you really need a feature that they don't have. Programming is awesome in part because we can build solutions on top of other pre-exsting solutions; it's 2017 and I can code Python in a web browser with interspersed markdown.
* Keep a diary. Write out problems and solution propositions first, if the solution is not trivial.
* Keep your mind clean, always finish what you started, so you can have completion and not clutter your thought process. This means not leaving code in a state of disarray, should compile when returned back to
* Let go. If the solution does not propose itself, take a break. Sleep over it. The solution will come, with time, not by bruteforcing of overdosing caffeine. Sometimes these work too, but as a habit, better to focus on long term goals than short term successes.
* KEEP IT SIMPLE. KISS! When solution starts to look too complex, it probably is. Break it down, simplify, line by line, so that the code is understandable and easy to read. Write for humans to read, not for machines to parse.
* There is no ready made solution. Accept the fact that to get results, work must be done and days and even weeks might go before getting there.
* It's ok to write code that is not "smart", that is not "perfect", that just freaking works right now as should and expected. It's just code, and in the end it all transforms into zeros and ones. Implement new features gradually towards more flexible and standardized solutions, first find a solution for the problem at hand and remember KISS again.
Some of the main points that come to mind. Especially the point of KISS, is so easy to go overboard with, starting to overthink all kinds of fancy structs, class inherintance models, whatever fancy code-beauty around a solution that could be solved with a simple function and evolved later if needed to something more flexible.
This KISS also applies to general software design, user interfaces etc also, probably the most useful habit is to remember when thinking about systems, keep it simple! It should also be fun to write at least in some level, if it feels like crap, don't do it for your own sake.
Put another way, working long hours is a bad habit because you end up solving problems the brute force way instead of figuring out how to come up with better solutions.
I think of this aiming towards becoming a 0.1× programmer: achieving same or better results with 1/10th the lines of code and effort. More here: https://codewithoutrules.com/2016/08/25/the-01x-programmer/
2. Avoid flow[0]. It's tempting, seducing and addicting, but you don't learn anything when you're in a state of flow. Anything sufficiently hard as to improve your skills should leave you feeling a little frustrated. Get used to that feeling.
3. Drop TV, Porn, news, music and video games. These things all give you rewards without having to do any work. In doing so, they steal your motivation and energy.
4. Stop eating sugar. If you want to get things done, strive for a steady blood sugar level. It's hard to work when your blood sugar drops and you fall asleep at your desk.
5. Sleep during the hours of 10pm and 2am[1]. That's when your body makes most of the hormones you need every day.
6. Do the opposite of this video: 7 ways to maximize misery by CGP Grey: https://www.youtube.com/watch?v=LO1mTELoj6o
[0]: http://calnewport.com/blog/2011/12/23/flow-is-the-opiate-of-...
[1]: http://www.anitarossiter.com.au/blog/early-nights-are-in-ord...
The whole point of point 3 is to work for your rewards instead of getting them instantly at the push of a button. It's too easy to get addicted to the latter and with any kind of addiction comes a decrease in motivation.
By all means, make your Skinner cage to lengthen assumed times for rewards, but make sure you can still run.
No fun allowed then?
A couple of ideas for taming it.
0) Media detox. It's can be so uncomfortable at first, feel what its like to go without for a week. A similar thing worked for me when I was trying to lose weight, getting used to fasting and what true hunger felt like allowed me to restrict my calories effectively without falling off the wagon.
1) Don't pick up new shows, finish out current seasons and leave it at that.
2) Make a rule that you won't watch TV/movies unless you are watching with someone else, so it's a social activity.
3) Only watch shows when you are working out, cleaning, other mundane task like that. Although you could go the other direction and say those are great activities to practice mindfulness with.
4) Pick one day/week to allow for watching things, ie Part of Sunday is just a lazy day in bed. Kind of like a cheat day.
#2 is a serious misunderstanding of flow[0] and is against research arguing that flow states facilitate learning[1].
Flow is not easy-peasy non-frustration time, it is getting "fully immersed in a feeling of energized focus, full involvement, and enjoyment in the process of the activity." To deny yourself that is blocking yourself from the most productive and rewarding of human experiences.
One of the fundamental ideas of flow is that when the task is challenging enough to break one out of the state, additional skills are learned to return to the flow state.[2]
In my opinion, to achieve your maximum potential as a programmer, you should be striving to hit a flow state as much as possible.
[0]: https://en.wikipedia.org/wiki/Flow_(psychology)#Education
[1]: https://www.learning-theories.com/flow-csikszentmihalyi.html
[2]: https://www.amazon.com/Flow-Psychology-Experience-Perennial-...
"Am I solving the problem at the correct level, using the appropriate method/technique/tool? Don't forget the big picture"
It's easy to just keep coding and add to existing code, architecture and methods. But sometimes the frog is starting to boil. Better then to re-evaluate whether to do some major refactoring, or add some layer of abstraction to keep it maintainable.
Sometimes you need to recognize that you're merely treating symptoms rather than a underlying problem. Sometimes you need to recognize that there are some library/tool/algorithm etc that can eliminate the need to solve a problem yourself.
2. Check your ego at the door. A good friend begins a class he teaches having coders say "I'm a programmer and I make mistakes"
3. I've seen a lot of simple systems that did useful things that grew into complex systems. I've never seen a system that started off complex being anything but a huge PITA for everybody involved. Keep It Simple, Stupid
4. Learn all the major programming paradigms and be able to solve problems in all of them. In my opinion, this is the first step to being any kind of programmer at all, much less a great one
5. We write code to help people. We write code alongside other people. People are a critical component, yet we hardly talk about them. Programming is about 95% social, 5% technical. But reading the latest industry news, you'd never think that. Keep your focus on the people, not the tech. Knowing and manipulating the tech is how you get in the game. How your work impacts real people is how you master it. You should be a professional and write clean code, but nobody cares about your standards if you're not getting along with others or making something somebody actually wants
6. Study mistakes and disasters. In every true professional field, folks spend a lot of time picking over and thinking about things when they go wrong. You should do the same. A big part of success is simple failure avoidance
7. Pair/mob program and use TDD if you're deep in OO or complex/mutable code. Nothing shows you how much you still have to learn like making what looks like a simple change and watching dozens of tests go red
8. Keep learning more about text processing and command line utilities. There are a ton of people right now writing complex code for things that can be done in a few lines of shell scripting. Don't try to solve everything in the shell, but know that a little bit of code can replace a ton of work if you know what you're doing.
9. Pick 2 or 3 IDE shortcuts and practice them each week. The less you touch your mouse and the more you can do work without moving your hands the faster you'll be. (This is one I need to work on)
10. Hang out with people that are better than you and pay attention. Greatness tends to rub off over time.
Seems to be Gall's law:
https://en.wikipedia.org/wiki/John_Gall_(author)#Gall.27s_la...
If you know how these things work internally you'll be 3x better than most programmers.
Fail as much as possible in an environment that is okay with failure. My environments have been side projects at home and professional work as well. Make sure you know why it failed and what you can do better next time.
2. Make it run
3. Make it work
4. Make it robust - Correct the errors
5. Make it failsafe - Handle the edge cases (out of memory, disk full)
6. Make it fast
7. Make it small
8. Make it clean (warnings, lint, beautify/style, clean up dead/commented code, in other words, polish the back of the cabinet)
I've met programmers in school who stop at #1 or #2. Most programming jobs get bogged down endlessly trying to get through the #4 backlog until the deadline comes along and they have to ship. Most developers, when asked to provide an effort estimate for a particular task only budget for #1, #2, and #3 (and with experience will learn to account for #4).
See videos like Gary Bernhardt - The Unix Chainsaw on how he gathers very nice data on just about anything in his system with a few pipes. It's easy to try to be awesome in OOP, or in javascript but waste time and energy clicking around or digging manually in repos for information.
I find that is the nicest and most efficient advice I ever took.
The other habit is: improving your maths skills (sophisticated combinatorics, probabilities, statistics) ..
http://bookofhook.blogspot.in/2013/03/smart-guy-productivity...
They are very concerned about compile times and having a short edit/compile/run cycle.
Attention to detail everywhere - be it code or design or documentation.
Communication skills - if one cannot communicate ideas, break them down and simplify them to oneself and others, the work will not really deliver a lot of value over time.
Curiosity to learn more and delve deeper to understand how things work (at a lower level).
Be lazy and optimize - optimize things, avoid repetitive work by building tools and tools that use tools.
"Limited resource" thinking - you may have 16GB RAM, a 4TB drive and a 100Mbps Internet connection, but your users may not. As much as possible, try to minimize things - the size of your program, the amount of data you store, the amount of data you transfer over the network, etc. It might sound silly, but this never goes out of fashion. It just comes back around once every few decades as we invent new devices and ecosystems with different constraints.
-
I'm not a great programmer myself but some of the habits I've developed and found effective are:
1. to start exercising.
I started running and going to the gym early last year and managed to make it part of my weekly routines now. I feel like I can focus on doing programming tasks much longer now. Oh, and it also helps me in term of accomplishing my short-term goals.
2. to always carry a book
Always be learning. Be it a medium articles, fiction or non-fictions, etc, it doesn't matter. As long as I am constantly learning new stuff, it's fine. It also help keep my ego in check since there are so much unknown I've yet to learn.
3. to stop whenever I'm feeling tired
I take a break from codes every now and then. Sometimes a few days or weeks. This allows me to avoid burnout which I've experienced once in the past.
It's not that everyone is full of beans, but what works for their environment doesn't necessarily work for yours. The best shoe size is 10 wide. I know, I've been wearing them for over 20 years.
Also test your assumptions. It's super simple to determine if doing it this way is faster/slower better/worse than doing it that way. Write a short script / console app prototype and put timers on it. It's much faster than arguing endlessly with someone over it. Collect some metrics.
This means that I often get bogged down in the finer details and corner-cases before even the most significant functionality is complete because I am trying to deliver a gold-plated, perfect, thought-of-everything solution the first time.
I've found time and time again that it really helps to take a step back, acknowledge to yourself and/or others that there will be TODOs, and start building up the core functionality piece-by-piece starting from the fundamentals and working your way up to the details & corner-cases.
That might mean you play around with a few approaches for an hour, pick one and then commit once, or it might mean that you go through many refactorings and commits over a period of days or weeks.
Whatever approach you take, I've found the feel-good factor/reassurance of having working-code but with known TODOs really helps keep me going and avoids me getting irritated/burnt-out fighting with problems before I've got anything working.
It is not going to be perfect first time, but "mighty oaks from little acorns grow" as they say.
tl;dr - get the fundamentals working first, refactor later to handle the edge-cases or make it sophisticated/elegant.
1. RTFM, I was told this for about every question I had as a beginner, and had to prove that I at least attempted a solution. This was before Q&A sites like we have now. 2. Learn to create head space, be that meditation, yoga, going for a walk, whatever it is for you. Find it and use it to your advantage. 3. Expand your consciousness - Understand you are not the center of the universe, how every you choose to get there.
The second is that the hardest won skill is getting things done. Whether you hate doing them, have done the thing 1M times before, are bored, or otherwise lack motivation. Applying yourself - really applying yourself only becomes possible when you have a reason to.
Always remember code does not capture the decision process it only captures the outcome.
How does what I do benefit the customer? What happens with this if I die tomorrow?
You can code the most elegant, clever and beautiful code in your pet projects but in a professional setting major importance lies in delivering values to the customer and writing code which can be handed over to be maintained by your successor.
Some concrete examples:
- you are using THREE.js. Try out raw webgl to draw a square. Run frighted back to THREE.js' arms and have some appreciation for what it is doing for you
- you are new to web development. Try working with the DOM directly. Then try something like knockout or angular that helps track dependencies between your view model and the dom. Then try out React. React has achieved wide-spread acceptance for a reason, I think it's the best pattern. But it's also the most abstract from the reality of what's happening underneath the hood, so taking steps up to the top can really help
- you are playing with scikit-learn and throwing various models at a classification problem. try implementing basic logistic regression using only numpy arrays. Try to understand how you could adapt your implementation `fit`, `transform` and `predict` interface used by sklearn.
A couple of recent articles that show this habit in practice:
https://zapier.com/engineering/how-to-build-redux/
https://medium.com/@karpathy/yes-you-should-understand-backp...
2. Be attentive to "flow" and how you achieve it. Space/surroundings, time of date, amount of time, etc.
3. Be aware of your energy level, and match the task to your energy level. Get away from the keyboard and get your brain engaged in other activities to keep you fresh and excited about programming.
4. Write great documentation. This takes as much practice as programming itself. Understand "great" is not equal to "a lot"
5. Don't overbuild on the first pass. Refactoring is your friend.
6. Prototyping is very valuable, but be aware the prototype that doesn't die. I tend to use languages that force the prototype to be thrown away.
7. Profile.
8. Always be learning about your craft and related areas. Business, design, security are all handy when you're a programmer.
9. Don't be a jerk.
10. Learn a variety of languages. You'll likely have a few favorite languages, which is fine, but always be picking up new ideas.
Thanks for making me smile.
* Always make a way to examine the data that's coming in (over network, arguments, whatever) to make sure your code is receiving the input it expects, and to be able to predict output/state changes.
* Similarly, have a way to see the data/state changes produced by what you wrote.
* Don't log all this by default.
* ...except for unexpected outcomes. By all means, check your inputs and loudly complain if they are garbage in a way that's unrecoverable.
* Be judicious about how much of this you normally expose to a user; don't overwhelm a user with unactionable noise.
You will move in the direction you face. If you look down on people your skill will diminish. If you look up to people your skill will improve.
Be a dilettante. Do general study of many different fields but recognize the limitations of your knowledge and show the appropriate respect to specialists and experts in their respective fields.
Pay close attention to your errors. Do root cause analysis on every error you make and formulate a plan of action to avoid it in the future.
Analyze your own habits and the habits of your peers. Seek to adopt practices that work for others where possible but only if they prove to work for you as well.
There are varying definitions of "understand", but I am confident that I understand something when I can give a lecture on it with no preparation... or when I can code it without checking any references.
Taking the time to properly understand the concepts, protocols, formats, apis and tools that you use when working on something.
This I never seem to have the time or mental energy to do.
2. No magic configurations. No implicit behaviors. Every optional behavior should be explicitly opt-in or opt-out.
3. Treat one as a special case of many. You will thank yourself later when you would otherwise curse the day you were born.
- Beginner's mind, with discretion
- Ability to avoid buzzwords / marketing mumbo jumbo and identifying true value (or lack of) of any tool
- Remembering you are here to solve a problem, beautiful code is not an end to itself
- Beautiful code is maintainable
- Maintainable code makes you productive
- Productivity is everything: The more problems you, can solve the better you are
- Personally, Hatha Yoga and certain related practices (Kriyas) have rejuvenated me every time I felt burnt out. I'm not a hippy new age shill and if you contact me, I'll share more information.
* Willing to learn new stuff and prove themselves wrong
* Talks to users
* Keep it simple. Nobody is impressed because it's overly complicated without a VERY good reason
Forgot to eat. Got sick.
Every programmer I admire has worked on their chosen field for years. You can keep flitting between languages and frameworks, but mastery ultimately comes from hankering down on one thing and advancing our collective knowledge a bit further. You can achieve mastery in any field - it can be a business domain - as mundane as a Time Tracking or a Todo list app, or it can be a technical domain - like compilers or databases or browsers. You however can't achieve mastery by consuming what others produce. Becoming an expert in CSS and its quirks is a good vocational investment, but you're no closer to a fundamental understanding of the field by just consuming an API.
You should spend years working on a problem domain that interests you. Look at prettydiff (https://github.com/prettydiff/prettydiff). It is a diff tool, a parser, a pretty printer, a minifier, all rolled into one. It is the most comprehensive publicly available tool in terms of language and dialect support in the world right now. Its code is not the most modular and new contributors might have trouble getting in, but its author has been at this problem for years, and if you called a conference for pretty-printing, he would be one among the few thousand people in the world to meaningfully participate.
Consider blueimp's jQuery File Upload plugin (https://github.com/blueimp/jQuery-File-Upload). While this isn't as foundational a work as prettydiff, the project spans seven years and a thousand commits. It solves a mundane problem, but the sheer effort that has went into it makes it a formidable solution.
Consider Martin Odersky, watch Compilers are Databases (https://www.youtube.com/watch?v=WxyyJyB_Ssc). He has been writing compilers for like forever. He's worked on the field for decades, and has written compilers for everything from Fortran to Java to Scala.
You don't have to be a genius to be a master. You just need to go as deep into a field as you can. Here are a few interesting links you might want to read:
The Joys of Having a Forever Project: http://web.archive.org/web/20130125011224/http://www.dev.gd/...
Rich Hickey on becoming a better developer: https://gist.github.com/prakhar1989/1b0a2c9849b2e1e912fb
You and Your Research by Richard Hamming: http://www.cs.virginia.edu/~robins/YouAndYourResearch.html
(...Don't polarize on one end of the Specialist vs Generalist debate.)
Since improvement of experience and quality of output is roughly logarithmic, it is (depending on the specialisation of the task at hand) better to have a person that has worked ten years to be 7/10 in 5 displines than 10/10 in one and 2/10 in the remaining 4.
Of course, if you only care about the one discipline, get the 10/10 guy. But in real use cases, things are only occasionally atomic, and lack of understanding of adjacent processes and disciplines can prove fatal.
Once everything is working then, if it's warranted, change the algorithm.
Usually great programmers are good at some of the above but never all, so you have to be clear about what you mean by great. After that its easy :)
Learn how to get paid when working for yourself.
Try to learn or at least play around with a new language every year.
Keep writing code.
Programming is the art of compromise. All solutions have pros and cons, the first thing to know is what things are more important than others in this situation (performance, maintainability, easy to program, etc, etc) and figuring how to deliver the optimal solution.
+
There is no one true way.
=
Anybody that claims that there is only one way to do something is selling dogma.
that and, listen to many voices, especially those that aren't the loudest.
Make it concise, not clever.
Keep functions short.
Small, frequent commits.
Instrument before you optimize.
2. All programmers should learn Galois theory, not only to get over the idea that they can't be good at math, but to learn to appreciate math. The book by Ian Stewart is good, although I would supplement it with Artin or Dummit and Foote.
3. Try to figure out why Ken Thompson and Dennis Ritchie did what they did, when they did it. Very important for getting a historical understanding of programming. Also, try to figure out why Ken Thompson said what he did in "Coders at Work".
4. Read The New Hacker's Dictionary.
5. Read Naive Set Theory
6. Try (and fail, at least for a year) to read A Shorter Model Theory (don't give up!)
7. Read Code Complete followed by the Python 2.x source code
8. Read SICP and write a scheme interpreter in a language of your choice
9. Implement a simple LR parser, instructions here: https://en.wikipedia.org/wiki/Simple_LR_parser
10. Play Kitten's game http://bloodrizer.ru/games/kittens/
11. Play the UC Berkeley CS 61a adventure game https://inst.eecs.berkeley.edu/~cs61a/reader/
12. Play JSRobowar https://statico.github.io/jsrobowar/
13. Read "Development of the C Language" https://www.bell-labs.com/usr/dmr/www/chist.html
14. Read "The Mythical Man-Month"
15. Read "Simply Scheme"
16. Read "The C Programming Language"