How can I become better at realizing how to solve a particular problem? - language-agnostic

I have become pretty fluent in a few different languages now, but I seem to have a hard time actually figuring out the best way to go about solving particular problems. What are some ways to go about getting better at the actual problem solving of programming.

Experience. Solving something completely new is hard. The best way to solve problems is to try and find a problem that you've solved before, and that is similar, and adapt you solution to the new problem. So until you have experience with many different kinds of problems, it's hard to solve new problems that you come across. Visiting sites like this and reading questions and theirs answers are a great way of learning how others solved problems that they encountered.

Basically, "just do it". When you have to make a choice, just make any choice (except flipping a coin).
Once you have something that works, then sit back and scratch your head about what you did wrong and how to do it better.
If you have absolutely no clue how to do even that, just solve a part of the problem completely and move on.
I suggest checking out this book. They aren't the best kid on the block, though they want us to think they are...but they did well with Basecamp.

When all you have is a hammer, everything begins to look like a nail.
So, make sure you're well versed in algorithms and data structures. When you study them, think hard about what sort of uses a particular algorithm is good for.

Ask someone else. Someone in your office, on Twitter or SO, or even your wife. People with no technical knowledge often come up with simpler solutions.
If you must solve it on your own, try one of these others:
Do a quick search for another person or project which has tried to solve your problem. If they have a blog, documentation or source code, you might be able to learn from their implementation.
Come up with at least TWO solutions and pick the best one.
Pretend you have 15 minutes to solve the problem before the civilized world is destroyed by Nuclear War / Skynet / Permanent endless re-runs of Seinfeld, you might think of something much simpler which gets 99% of the work done.

The book is a set of heuristics to go through when solving a problem. Read about it on Wikipedia. Buy it on Amazon.

By solving actual problems. Practice makes perfect.
If you have time to become fluent in multiple languages, my guess is that you haven't spent much time doing any actual work. If you have a job, it might be time for a new one. If you're still in school, do you have any interest in starting a project for yourself or contributing to one that you use regularly?
It might help to know what kinds of problems you're having difficulty solving.

Go find an open source or free project you can get excited about and contribute. I learned a lot by signing up to code for my favorite video game modification.

Experience.
Study really only goes so far. Find something fun and small. Do it.

One way that seems to work for a lot of people is to pick use a book like Programming Challenges as a guide, and focus on solving problems of a particular type. For example if you're weak in an area like graph problems or dynamic programming, find a set of problems on an online judge and work through them. You'll start to recognize patterns and be able to classify problems.

Google for an answer. Chances are someone else has solved the same problem or a similar problem before.
Ask on SO. :)
Read some textbooks or online articles about design patterns.
Problems may have many solutions, some simpler and some more complicated. Don't get stuck thinking there is only one solution. Just go with the simplest solution that makes the most sense in the context of your application.
After years of experience you'll be able to think of your own solutions to most problems. :)

Study Algorithms!
Search and get a hold on as many examples, books on the subject programming or otherwise, etc.
Problem solving skills can also be improved by playing tactical games.
These made me Enjoy problem solving and become better (not necessarily good) at problem solving:
Chess and igo

I like this general method:
List the possible solutions with their strengths and weaknesses
(This will push you to briefly taste all of them)
Chose the best one and make your design on it
(If you find any heavy obstacle, reconsider other options)
Implement
most importantly, on every step, learn

The best way is probably to learn form a master if that's an option. Especially if you can find someone familiar with the problems your addressing.
Generally the more tools we have at hand the more options we have for tackling a problem. I agree that's important to always code and to always deliver something that works (however inelegant it is). But I think we need to increase our skills/knowledge in many directions:
Language skills (know your language(s) in depth)
Programming paradigms (Imperative, Object, Functional)
Framework knowledge
Algorithms
Patterns
Date-Structures
Methodologies (Agile, DDD, BDD, ?DD)
Tools
etc
You can get a lot of skill through on the job just-in-time-learning, but I usually have a pet subject at any time that I'm trying to get a deeper understanding of, typically this means getting the book and reading it cover to cover.

Work your way through Project Euler, and look at other people's solutions to the problems. Almost every problem will have been solved in a way that wouldn't have occurred to you, and usually with greater efficiency.

I think that there is a lot more than raw experience involved in becoming a good problem solver - because I've seen poor problem solvers with lots of experience.
Here are a few tips but you can find many more around the web.
Look at a number of problems and
figure out what they have in
common. The greater the generality
with which you understand the
solution to a problem, the more you
can apply it to other problems.
Try to discover approaches which
good problem solvers use to solve problem. But don't assume anyone has monopoly on problem solving
If you read Richard Feynman's
books, you'll notice that he
considers many different routes to
get to his goal. Don't narrow your
approach prematurely
Be positive. Assume that you can find
the solution to anything. Your state of mind matters. Enjoying the process of problem solving makes it much easier
Don't beat your head against the wall. If you don't
seem to be making progress with one approach, try another approach
Always be looking for more ways of
solving problems and more insights
into the process of problem solving itself
Be willing to work. It still can take a lot of effort solve some problems
The more different fields of study you know, the more viewpoints you have. I have a strong math background and I find it very useful for many problems. Physics, music or any different viewpoint might be useful

Practice solving problems.
Take an algorithms or discrete math course.

Here some tools that I've used in the past to help me understand a particular problem and its solution. I don't always use them today, but they helped me to learn how to think about breaking down a problem and coming up with a solution.
Class-Responsibility-Collaboration (CRC) cards
One card per class, details the responsibility of the class and what other classes it collaborates with. Using cards you can layout your design for the solution and see where you have too much coupling or too much responsibility. They allow you to think about the design in a lightweight manner before committing to code.
Use cases
Either actual structured use cases that describe user interaction with the system or even briefer stories or story cards. I still use stories, though I capture them in a wiki instead. This allows you to capture the interaction with the system in an informal way. Stories are basically placeholders for conversations that you need to have with the customer about what is supposed to be done. Using the collected stories, you start getting a grasp on the overall intention of the code. You can also start seeing how things interact and what works with other things. This is really the beginning of design.
UML Diagrams - particularly interaction diagrams
For awhile I used these a lot. It really helped to see how things actually worked together under the hood. I will still diagram, informally, some complex interactions to make sure I don't miss anything important. Going through a lot of these really helped me to think about how my objects interacted and now it is sort of second nature to think in terms of interactions.
Class diagrams -- a really high level view of the code.
These allow you to see your code structurally, especially if you can break the diagram down into components or layers of architecture. Mostly I use these now to explain the code to other people when necessary. When starting out these provide a pretty good visualization, though, if you're struggling with the bird's-eye view of the code.
The best advice I can give you if you try these is to follow the "rules" until you really have a good grasp of what is going on. Once you feel like you have a better understanding of what they provide, you can use them or not, or modify how you use them to keep only what is helpful and let the other stuff go.

Related

Why do newbie programmers seem to shy away from libraries? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I've noticed many questions on here from new programmers that can be solved using libraries. When a library is suggested, often times they respond "I don't want to use X library" Is it the learning curve? or ? Just curious!
A lot of new programmers are still working at a very low level of abstraction, learning the trade. That's something everyone has to go through. It takes a while to "move up the stack" so to speak.
Once programmers realise that they spend most of the time solving the same problems as someone else already did, and the goal is to realise "business value", then they can really appreciate the value a good library brings.
When you're still learning the ins and outs of a new language, also having to learn how to use a 3rd party library can look like too much work. Also, libraries tend to be badly documented - or at least have documentation that seems totally opaque to a new(er) programmer.
So, faced with trying to solve problem X, saying "use a library" can sound a lot like "solve problem Y THEN problem x".
(Also, their professors told them not to. I managed to get all the way though my undergrad in C++ without learning the STL existed. Boy, did THAT cook my noodle.)
Some people, when confronted with a
problem, think “I know, I'll use a
library.” Now they have two
problems.
Seriously - this is a reasonable way for a newbie, already overwhelmed by new language, programming environment, paradigms, keystrokes, etc. to react to the suggestion to use a library. If you've got a solution, but it's not working, there are many potential sources of error; sorting through them is a challenge. Adding to them can seem irrational.
"Use a library" means find the library, download it, install it in your project, and call the necessary function. Not hard, if you're used to it (and there aren't corporate policies against it, and you have reason to trust the vendor, and the library itself has minimal dependencies, etc.). But if it's all new to you, when you ask a programming question and get back a system configuration answer, it can seem unhelpful (even if it is not, in fact).
Almost always it's because their professor has told them that they can't.
Sometimes it's just because they want to learn it themselves, but I'd say that's rare.
It's the learning curve.
Using libraries is probably one of the worst things a learning programmer can do. Instead of learning how to code, they're learning how to use specific APIs that other people implemented. I'm not saying that every programmer has to understand every single thing that they use, but programmers who know the ins and outs of a computer (digital logic, assembling op-codes, etc) usually have an edge over people who've started with something like Java Swing and are just throwing together libraries.
In production, this is a different matter of course. But I think the best course of education is to 'make everything' once, at least. Writing my own web application framework from the ground up really improved my programming skills and abstract abilities. Doesn't mean I'll use that framework if someone hires me to build them an application, but I know the strengths, weaknesses, and reasons behind the things that the 'giant' frameworks use, and it can help me choose a particular framework for a particular situation.
I remember shying away from several libraries simply because I wanted to see if I could create my own algorithm. I didn't want to just give up and let someone do the work for me but rather I wanted to learn from my mistakes. Once I had come up with a solution I was happy with, I looked into the libraries.
So for me it was simply wanting to see if I could do it.
I always have this urge to do it myself, but sometimes I can see my own limitations.
Just recently downloaded a library to create PDF documents, but thats pretty much the only time I can remember.
At least for me, (trying to) do things myself, is my way of learning.
My impression is that many newbie programmers wouldn't consider it their own work if they were to use someone elses libraries.
I don't think that this is necessarily a bad thing. Using libraries is great; it saves time, effort, bugs, etc. However, you learn very little in the process, and for new programmers, learning is the goal. To answer the question, I think that they tend to shy way from libraries simply because they are not used to using them and perhaps they don't know that they exist.
For many poorly documented libraries that are either implemented loosely or in languages that don't allow you to control containment and visibility very well, it can be quite difficult to guess just how the library is supposed to be used.
After you've used it for a while, you've gotten used to the quirks or read other source code that taught you the right way; but until then it can be pretty irritating to use a poorly put-together/designed library. (or even a well designed one that isn't terribly well documented).
If you don't have the source code to the library, that's another problem--you have no control over the ability to keep your program working. This is much more rare these days, but still happens in the case of a purchased library.
Most of the points covered off (for me the main one is the learning curve) but one other I think plays a part:
Because learning about a library is less exciting than coding the same functionality yourself.
More libraries = less billable hours.
I think there's a lot of time that needs to be invested in understanding the library's purpose - yes, a learning curve, but it's more that newbie programmers probably don't know what they need until they have a lot more experience.
Because it's fun.
Because part of maturing as a developer is learning to quickly identify problems which can be solved by a library or existing solution and which need personal attention.
When you're trying to learn how to do things, anytime something is accomplished "magically" by calling AwesomeClass.doAwesomeStuff(), you end up giving away a portion of control. When you are "new" and don't know what you're giving away or why it can be unsettling. This was my primary knock against Rails when I was first learning it. So many things just "worked" and I didn't know why without digging through lots of Rails source (which I generally didn't have time to do).
At least, that's my take on it.
The same reason that more experienced developers do -
Because it can often be as difficult to learn how to use a library as to write the part of it you need yourself. And at least then you can understand how it works when it doesn't do what you expect.
An experienced developer just has experience at understanding how to use libraries so more likely to consider it. An inexperienced developer it's one more thing to learn...
I'm a programmer, not a psychologist! :)
It was a long, long time ago for me, but it was because I wanted to learn and experience. I didn't want to use something I did not understand, so if I didn't think I understood the library and could program it myself, I tried not to use it. There might have been a bit of fear too; programming gives you a feeling of control, and using a library is like giving away this control.
Answer from a noob -
"I am not sure how to use the libraries or even how to access them or how it works"
Libraries often come with the overhead of learning some API and it's paradigm. It can get complex fairly quickly, and I could easily understand that beginners would prefer something a bit more in their comfort zone. From my experience, I found most libraries & frameworks seem to do a great job abstracting some tedious routine, but when I need to either extend this functionality, or use it in a way that's not intended, it can be a handful.
I think it's one of those things where "practice makes perfect".
Well, the newbie's purpose might be more solving the problem than implementing a solution. Perhaps what they really want to do is figure out how to solve the problem. I mean, if they're still heavily in the learning phase, it's quite possible they don't want easy answers handed to them.
I think the professors want them to stick to the basics. When I graduated from under-grad school, I knew C++, Java and some other languages but had no clue about libraries and frameworks being used in companies. It was like do you know java..yes..can you write a servlet..no.
For speed demons they rarely use 3rd party libraries and new programmers are usually looking to squeeze every once of speed of of their code. I think if they don't have control over their code they can't get the performance that they are looking for. At least thats why i avoided libraries when I first started to program.
I remember programing my first DAL and avoided all the other free libraries out on the web because I wanted my code to perform at top speed. Later, I discovered that usually its not the code thats the bttleneck its actually the database.
Some open source libraries are buggy or not as efficient as others.
In my eyes another factor is that additional libraries add complexity. Programs tend to get harder to understand, harder to maintain and buggier when getting more complex. I think what makes especially new programmers shy away from libraries is that adding library code increases complexity more than adding your own code - simply because understanding how the library works is still out of their grasp. So it seems to be a problem of both skill and psychology.
I think more fundamental issues can be recognized as a deterrant to using existing libraries.
Part of this as "newbie programmers" is a lack of exposure to libraries. If you don't know they exist, how do you know to use them?
Number Of Options Available. Let's say I'm really interested in learning more about MVC, but if I have to choose between cakephp and smarty and zend and ... well you can quickly see the gears work to discover a way to achieve the goal without investing the time experimenting. Take a look at Freshmeat or SourceForge to get a better understanding at the daunting selection of libraries available.
Questionable support combined with sketchy/outdated documentation for the libraries. Do I want to use this tool that may no longer work or may be abandoned in the future? It is likely that a project will evolve, and so it will for the project of a library too. Will its usefulness last the lifetime of my project or will I be required to re-do this work again?
Using a library requires you to understand the relatively complex design of the library, something that new programmers might not have mastered because all they've ever written is simple/procedural/single-purpose code. For example, to an experienced programmer standard design patterns like template method, observer and command seem pretty obvious, but to a newbie it all just seems like magic and/or unnecessary complexity. For me the turning point was when I got good enough to grok design patterns and write some basic reusable code.
It's been a long time now, but when I came out of college, I knew nothing of libraries. This was in the days of mainframes and mini-computers. Our college had a VAX and the managers were paranoid about students hacking the system, so didn't allow us to even see the library manuals. So, when I first came out of college, I didn't even think of libraries being available.
I am sure there are a lot of reasons why the newbie doesn't want to use the new library. But wouldn't this be a good opportunity, if you have enough time, to show them what the advantage of using the library is? With the people I work with, I will usually provide an example of why something is better than their approach. It helps them learn and mature as a programmer.
Happens that noobs use Libs without knowing, but when they must import/add one that is fairly less documented, there is a fear of unknow. That happens mostly for compiled langs!
In the interpreted, (or compiled IRT), mainly when there is a console, such fear is almost non-existent; since you can require and see if it fails, call a method and see what it returns.
Consoles are tools of bravery !

How to tell someone that their mod's to my program are not good?

G'day,
This is related to my question on star developers and to this question regarding telling someone that they're writing bad code but I'm looking at a situation that is more specific.
That is, how do I tell a "star" that their changes to a program that I'd written are poorly made and inconsistently implemented without just sounding like I'm annoyed at someone "playing with my stuff"?
The new functionality added was deliberatly left out of the original version of this shell script to keep the it as simple as possible until we got an idea of the errors we were going to see with the system under load.
Basically, I'd argued that to try and second guess all error situations was impossible and in fact could leave us heading down a completely wrong path after having done a lot of work.
After seeing what needed to be added, someone dived in and made the additions but unfortunately:
the logic is not consistent
the variable names no longer describe the data they contain
there are almost no comments at all
the way in which the variables are used is not easy to follow and massively decreases readability and hence maintainability.
I always try and approach coding from the Damien Conway point of view "Always code as if your system is going to be maintained by a psychopath who knows where you live." That is, I try to make it easy for follow and not as an advertisement for my own brilliance. "What does this piece of code do?" exercises are fun and are best left to obfuscation contests IMHO.
Any suggestions greatly received.
cheers,
I would just be honest about it. You don't necessarily need to point every little detail that's wrong, but it's worth having a couple of examples of any general points you're going to make. You might want to make notes about other examples that you don't call out in the first brief feedback, in case they challenge your reasoning.
Try to make sure that the feedback is entirely about the code rather than the person. For example:
Good: The argument validation in foo() seems inconsistent with that in bar(). In foo(), a NullPointerException is thrown if the caller passes in null, whereas bar() throws IllegalArgumentException.
Bad: Your argument validation is all over the place. You throw NullPointerException in foo() but IllegalArgumentException in bar(). Please try to be consistent.
Even with a "please," the second form is talking about the developer rather than the code.
Of course in many cases you don't need to worry about being so careful, but if you think they're going to be very sensitive about it, it's worth making the effort. (Read what you've written carefully, if it's written feedback: I accidentally included a "you" in the first version to start with :)
I've found that most developers (superstar or not) are pretty reasonable about accepting, "No, I didn't implement that feature because it has problem X." It's possible that I've been lucky though.
Coming from the other perspective, I would encourage you to think about it in their shoes. I will describe a "hypothetical" experience.
Some things to keep in mind:
The guy was trying to do something
good.
Programmers are terrible at
mind reading. They tend to only know
what they read.
He may have not been given complete guidance as what needs to be done(or what doesn't need to be done)
He is likely doing the best he knows how to.
Just keep that in mind and talk to them. Teach them. No need for yelling or pissing contests. Just remember that they are not intentionally trying to make your life difficult.
I see that you've asked a lot of questions about how to deal with certain kinds of developers. It seems to be a common thread for you. You keep asking about how to change people around you. If this is a constant problem for you, then perhaps you are the problem.
Now I know you are asking questions to learn how to deal with people you find difficult, and that's good, however, you keep asking (and getting answers) about how to change people.
It seems to me that you need to change. Work with these people to change the code to what you want it to be. With them. Don't try to get them to do it. Just do it, and tell them what you did and why, and ask suggestions for further improvement, and learn from each other. Play off of each other's experience and strengths. Just my 2 cents.
If you have clearly defined coding standards for the project, point out that the code needs to be changed to meet those standards. The list you have there seems like quite reasonable feedback (though #3 is much argued-over; I would only push to document the really confusing parts as fixing the other three points, hopefully, makes the code less confusing).
If there are any other examples you have in your repository from this developer that are several months old, show one to him and ask him what it is doing. (Show him this one in a few months). When he has to zip around to find out what is actually in his variables, and deconstructing every line of code to figure out what it is doing. Break into a code review / pair programming session right there. Refactor and rename together so that he hopefully begins to see for himself exactly why these things are important.
Frankly, I think this is a political problem, not a coding problem. Specifically...
WHO SAID THIS PERSON WAS A "STAR"? If this is the same person you described in your other question, then you already have your answer there: THIS PERSON IS NO "STAR".
So then you get into the other effects of politics...
Who is claiming this person to be a star? Why can you not just tell the person "this is crap code"? Who is protecting them / defending them were you to do that? Can you do that or would you get blasted / demoted / put on the "to be laid off" pile?
You are asking questions that cannot really be answered in isolation. IF the code is crap, then throw it away and do it correctly yourself. IF there are reasons that you cannot do that, then you need to ask yourself if the benefits of this place outweigh the negatives.
Cheers,
-R
Creating a program and then releasing it to be worked on by other developers is tough. You are throwing your code to the mercy of others' development styles, coding conventions, etc.
Telling those developers that they are doing coding poorly, after the code is in, is one of the hardest things that you can do. It is best to address your concerns before they ever start working with your code. This can be done in two ways: Maintaining a detailed coding standard, requiring that submitted code adheres to this and maintaining a development road map, not to just outline when new features will be in, but to create dependencies to avoid such mishaps.
More to your situation, it is important not to criticize or it could cause hostility and worse code coming in. Maybe you can work with that developer to create standards documentation. You will be able to express your ideas about what the standards should be, and you will get their input, without causing any hard feelings.
Always point out the good things in their code, and be sure when discussing the weaknesses that you frame them pointing out the reasons that it will benefit everyone (the developer included), never criticize.
Good luck.
I would do the following:
Make sure he knows that his hard work is appreciated (preferably, this should be the truth)
Ask him if he would mind making a few changes, making it sound like no big deal and easy to fix
Explain the issues, including why they are issues, and suggest specific changes to set him on the right path.
Hopefully, the exercise will help him integrate into the culture project better.
We try to solve these potential 'issues' proactively:
Every 'bigger' project where people work together gets assigned a project 'codelead' (one of the developers). This rotates every project (based on preferences, experience with the particular task ...) so everyone gets to be in the 'contributing' and 'code-project-lead' roles once in a while.
We explicitely made an agreement that
these project 'leads' can decide
whatever they want to with the code
contributions of the others (sort of
like a temporary dictatorship: change
it, make suggestions, ask people to
redo stuff etc.). The projectcode
'lead' bears the complete
responsibility for the aggregated
code to work.
With these formalised 'leads' (and the changing roles) I think people have less problems with (constructive) criticism of the parts they contribute.
Yes, keep the feedback as appreciative, professional and technical as possible, back up your concerns with possible "worst case" scenarios so that the disadvantages of those features and/or this particular implementation, become blatantly obvious.
Also, if this is about features/code that are very specific and are not of any use to most users, express your concerns about the code/use ratio - indicating concerns about increased code base complexity etc.
Ideally, present your concerns as open-ended questions - in the sense of: "Though, I am wondering if this way of doing it may work in the long term, due to ...". So that you actually encourage an active dialogue between contributors.
Invite your fellow contributors and user to provide their opinions on these concerns, in fact ask other people/contributors what they are thinking about this addition (in terms of pros & cons, requirements, code quality), do make the statement that you are willing to reconsider your current position if other contributors/users can provide corresponding insight.
You are basically encouraging an informal review that way, asking your community to also look into the proposed additions, so that the advantages and disadvantages can be discussed.
So, whatever the decision will be, it will be one that is community-backed, and not just simply made by you.
You being the architect of the original design, are also in an excellent position to provide architectural reasons why something is not (yet) suitable for inclusion/deployment.
If stability, complexity or code quality are a real concern, do illustrate how other contributions also had to go through a certain review process in order to be acceptable.
You can also mention how specific code doesn't really align with your current design, or how it may not scale too well with future extension to your current design, similarly you can highlight why certain stuff was left out explicitly.
If you actually like the features or the core idea, be sure to highlight the excellent addition these features would make if properly implemented and integrated, but do also highlight that the existing implementation isn't really appropriate due to a number of reasons.
If you can, do make specific suggestions for improvements, provide examples of how to do things better, and what to avoid and do express that you hope, this can be reworked to be added with the help of your project's community.
Ideally, present your requirements for actually accepting this contribution and do mention the background for your requirements, you may in fact say that you hate some of these requirements yourself.
Preferably, present and discuss instances where you yourself contributed similar code (or even worse code) and that you ended up facing huge issues due to your own code, so that these policies are now in place to prevent such issues. By actually talking about your own bad code, you can actually be very subjective.
Emphasize that you generally appreciate the effort itself, and that you are willing to provide the necessary help and pointers to bring the code in question into a better shape and form. Also, encourage that similar contributions in the future should be properly coordinated within your community, in order to avoid similar issues.
Always think in terms of features and functionality (and remind your contributor to do the same), not code - imagine it like a thorough code review process, where the final code that ends up being committed/accepted, may have hardly anything in common with the original implementation.
This is again a good possibility, to present examples where you yourself developed code that ended up largely reworked, so that much of it is now replaced by a much better implementation.
Similarly, there's always the issue with code that has no active maintainers, so you can just as easily suggest that you feel concerned about code that may end up being unmaintained, you could even ask if the corresponding developer would be willing to help maintain that code, possibly in a separate branch.
In the same sense, always require new code to be accompanied with proper comments, documentation and other updates. In other words, code that adds new or changes existing functionality, should always be accompanied with updates to all relevant documentation.
Ultimately, if you know right away that you cannot and will not accept any of that code in the near future, you can at least invite the developer to branch or even fork your project, possibly in you repository and with your help and guidance, so that you still express your gratitude for working with your project.

How to convince your fellow developer to write short methods?

Long methods are evil on several grounds:
They're hard to understand
They're hard to change
They're hard to reuse
They're hard to test
They have low cohesion
They may have high coupling
They tend to be overly complex
How to convince your fellow developer to write short methods? (weapons are forbidden =)
question from agiledeveloper
Ask them to write unit tests for the methods.
That depends on your definitions of "short" and "long".
When I hear someone say "write short methods", I immediately react badly because I've encountered too much spaghetti written by people who think the ideal method is two lines long: One line to do the tiniest possible unit of work followed by one line to call another method. (You say long methods are evil because "they're hard to understand"? Try walking into a project where every trivial action generates a call stack 50 methods deep and trying to figure out which of those 50 layers is the one you need to change...)
On the other hand, if, by "short", you mean "self-contained and limited to a single conceptual function", then I'm all for it. But remember that this can't be measured simply by lines of code.
And, as tydok pointed out, you catch more flies with honey than vinegar. Try telling them why your way is good instead of why their way is bad. If you can do this without making any overt comparisons or references to them or their practices (unless they specifically ask how your ideas would relate to something they're doing), it'll work even better.
You made a list of drawbacks. Try to make a list of what you'll gain by using short methods. Concrete examples. Then try to convince him again.
I read this quote from somewhere:
Write your code as if the person who has to maintain it is a violent psycho, who knows where you live.
In my experience the best way to convince a peer in these cases is by example. Just find opportunities to show them your code and discuss with them the benefits of short functions vs. long functions. Eventually they'll realize what's better spontaneously, without the need to make them feel "bad" programmers.
Code Reviews!
I suggest you try and get some code reviews going. This way you could have a little workshop on best practices and whatever formatting your company adhers to. This adds the context that short methods is a way to make code more readable and easier to understand and also compliant with the SRP.
If you've tried to explain good design and people just aren't getting it, or are just refusing to get it, then stop trying. It's not worth the effort. All you'll get is a bad rep for yourself. Some people are just hopeless.
Basically what it comes down to is that some programmers just aren't cut out for development. They can understand code that's already written, but they can't create it on their own.
These folks should be steered toward a support role, but they shouldn't be allowed to work on anything new. Support is a good place to see lots of different code, so maybe after a few years they'll come to see the benefits of good design.
I do like the idea of Code Reviews that someone else suggested. These sloppy programmers should not only have their own code reviewed, they should sit in on reviews of good code as well. That will give them a chance to see what good code is. Possibly they've just never seen good code.
To expand upon rvanider's answer, performing the cyclomatic complexity analysis on the code did wonders to get attention to the large method issue; getting people to change was still in the works when I left (too much momentum towards big methods).
The tipping point was when we started linking the cyclomatic complexity to the bug database. A CC of over 20 that wasn't a factory was guaranteed to have several entries in the bug database and oftentimes those bugs had a "bloodline" (fix to Bug A caused Bug B; fix to Bug B caused Bug C; etc). We actually had three CC's over 100 (max of 275) and those methods accounted for 40% of the cases in our bug database -- "you know, maybe that 5000 line function isn't such a good idea..."
It was more evident in the project I led when I started there. The goal was to keep CC as low as possible (97% were under 10) and the end result was a product that I basically stopped supporting because the 20 bugs I had weren't worth fixing.
Bug-free software isn't going to happen because of short methods (and this may be an argument you'll have to address) but the bug fixes are very quick and are often free of side-effects when you are working with short, concise methods.
Though writing unit tests would probably cure them of long methods, your company probably doesn't use unit tests. Rhetoric only goes so far and rarely works on developers who are stuck in their ways; show them numbers about how those methods are creating more work and buggy software.
Finding the right blend between function length and simplicity can be complex. Try to apply a metric such as Cyclomatic Complexity to demonstrate the difficulty in maintaining the code in its present form. Nothing beats a non-personal measurement that is based on testing factors such as branch and decision counts.
Not sure where this great quote comes from, but:
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it"
Force him to read Code Complete by Steve McConnell. Say that every good developer has to read this.
Get him drunk? :-)
The serious point to this answer is the question, "why do I consistently write short functions, and hate myself when I don't?"
The reason is that I have difficulty understanding complex code, be that long functions, things that maintain and manipulate a lot of state, or that sort of thing. I noticed many years ago that there are a fair number of people out there that are significantly better at dealing with this sort of complexity than I am. Ironically enough, it's probably because of that that I tend to be a better programmer than many of them: my own limitations force me to confront and clean up that sort of code.
I'm sorry I can't really provide a real answer here, but perhaps this can provide some insight to help lead us to an answer.
Force them to read the book "Clean Code", there are many others but this one is new, good and an easy read.
Asking them to write Unit tests for the complex code is a good avenue to take. This person needs to see for himself what that debt that complexity brings when performing maintenance or analysis.
The question I always ask my team is: "It's 11 pm and you have to read this code - can you? Do you understand under pressure? Can you, over the phone, no remote login, lead them to the section where they can fix an error?" If the answer is no, the follow up is "Can you isolate some of the complexity?"
If you get an argument in return, it's a lost cause. Throw something then.
I would give them 100 lines of code all under 1 method and then another 100 lines of code divided up between several methods and ask them to write down an explanation of what each does.
Time how long it takes to write both paragraphs and then show them the result.
...Make sure to pick code that will take twice or three times as long to understand if it were all under one method - Main() -
Nothing is better than learning by example.
short or long are terms that can be interpreted differently. For one short is a 2 line method while some else will think that method with no more than 100 lines of code are pretty short.
I think it would be better to state that a single method should not do more than one thing at the same time, meaning it should only have one responsibility.
Maybe you could let your fellow developers read something about how to practice the SOLID principles.
I'd normally show them older projects which have well written methods. I would then step through these methods while explaining the reasons behind why we developed them that way.
Hopefully when looking at the bigger picture, they would understand the reasons behind this.
ps. Also, this exercise could be used in conjuction as a mini knowledge transfer on older projects.
Show him how much easier it is to test short methods. Prove that writing short methods will make it easier and faster for him to write the tests for his methods (he is testing these methods, right?)
Bring it up when you are reviewing his code. "This method is rather long, complicated, and seems to be doing four distinct things. Extract method here, here, and here."
Long methods usually mean that the object model is flawed, i.e. one class has too many responsibilities. Chances are that you don't want just more functions, each one shorter, in the same class, but those responsibilies properly assigned to different classes.
No use teaching a pig to sing. It wastes your time and annoys the pig.
Just outshine someone.
When it comes time to fix a bug in the 5000 line routine, then you'll have a ten-line routine and a 4990-line routine. Do this slowly, and nobody notices a sudden change except that things start working better and slowly the big ball of mud evaporates.
You might want to tell them that he might have a really good memory, but you don't. Some people are able to handle much longer methods than others. If you both have to be able to maintain the code, it can only be done if the methods are smaller.
Only do this if he doesn't have a superiority complex
[edit]
why is this collecting negative scores?
You could start refactoring every single method they wrote into multiple methods, even when they're currently working on them. Assign extra time to your schedule for "refactoring other's methods to make the code maintanable". Do it like you think it should be done, and - here comes the educational part - when they complain, tell them you wouldn't have to refactor the methods if they would have made it right the first time. This way, your boss learns that you have to correct other's lazyness, and your co-workers learn that they should make it different.
That's at least some theory.

Are there any strategies to avoid satisficing?

Satisficing (a portmanteau of "satisfy" and "suffice") is a decision-making strategy which attempts to meet criteria for adequacy, rather than to identify an optimal solution. A satisficing strategy may often be (near) optimal if the costs of the decision-making process itself, such as the cost of obtaining complete information, are considered in the outcome calculus. (Source)
Most decisions in software engineering are easy enough to take without pondering for hours on the subject. The first solution that comes to mind is usually good enough, so we can quickly use that and proceed to the next decision.
However, there are also those rare cases where you have to solve a more difficult and / or critical problem. Those problems can cost you a lot of money or time when solved in a suboptimal way.
In those cases I am usually trying to come up with several completely different solutions/approaches of solving the problem. I then pick one and refine it until I am fully satisfied with my solution.
Usually this works, but sometimes I can only come up with one adequate, but not really good, solution. I am aware that my solution is not very good and the problem is critical enough to warrant some more effort. However, knowledge of the solution I already found blocks my creativity, so I just can't find a second one (at least not right away). I am stuck with my mediocre idea and, unless I can ask someone else, I have to implement it to move forward.
Are there techniques to overcome this? The two things I can think of is holding a brainstorming session with someone else or going for a walk.
What do you do in those cases?
I would normally have two problems with putting a problem aside for a week: a) my boss probably wouldn't go for it because the business will usually need a solution sooner as opposed to later, and b) I have the attention span of a gold fish, so if I drop a problem for that long, I will have to take time to walk through the problem because I've filled my brain with dozens of other problems in the meantime.
That's not entirely bad, because sometimes I do find a better, more elegant solution when I'm forced to refresh myself on the code and the business constraints that define the problem, but sometimes I just spend half a day running myself into the same dead-ends.
All that being said, the idea of putting a problem aside is a good one, but it's the time frame that's important. I've often realized a solution while eating breakfast the morning following an end of the day spaghetti-code brain lock up fiasco.
Trying to articulate the problem to colleagues often helps, just because the effort will expose gaps in your understanding of the problem. Usually the other person won't find a better solution unless they're actually working with you on the problem from the beginning, just because they won't understand all the constraints that you've probably spent days mapping out in your head.
To answer the original question, my preferred method after taking a break and running it by some colleagues, is to implement the adequate solution and just get something working.
One reason is that if the client decides that wasn't what they wanted, because they never really know what they want in the first place, you won't have spent too much time on something that'll be thrown out anyway. Another reason is that the adequate solution might just be that: adequate. You can move on. The best reason is that an implementation gets you into the hard questions quickly, and from there you might start to see a better solution.
It's like building models as an architect. You can do lots of drawings, and even spend a lot of time on nice renderings, but it's really more effective to quickly get a glue gun and starting throwing cardboard models together. Once you can see it in 3D you can start to see where things don't line up properly, and you haven't wasted your time on nice renderings that will gloss over the shortcomings.
In my experience I address that by putting the problem aside for a while, say a week. Let it rest. Then come back with a fresher mind and you'll start to see things you didn't before.
Of course, YMMV.
Describe the problem to someone else and ask how they would solve it. Sometimes it'll be the same solution you came up with, in which case, point out the flaws you've already perceived in it and continue the dialog.
Sometimes it'll be a solution you didn't think of, or one that helps you solve problems with the solution you did have in mind.
However it works out, I've found discussing the problem with others to usually be a very beneficial strategy.
I know this is a bit heretical but I find writing documentation for the solution helps. Just putting it down on paper forces you to think and organize the problem differently than coding on it. Attempting to describe the solution in terms of the business problem tends to help point out were the gaps lie and these in turn suggest alternate solutions. In the best cases you end up with new approaches. At worst, you end up with documentation. Give yourself a set amount of time. Start with an outline and work until you run out of time, you complete the documentation or you are inspired with alternate solutions.
Satisficing is the technique that gave birth to AI. Some very important software, including driving direction generators and network routing are both done based on a tradeoff of efficiency for completeness.
The best way to deal with this issue is to implement the solution, and fix the incomplete parts of it when and if it becomes apparent that other parts of the project require it to be fixed.
Obviously there's a lot of room to go in the wrong direction on this one and end up with something sloppily put together, but keep in mind that the context of the entire system is where the quality of what you write is going to be measured.
I find it useful to stop looking at the solution, and start looking at the problem. Maybe I am trying to solve the wrong problem. Look, and see if there is actually a different problem there. If you feel that your solution is only 'adequate', it could well be because it's not addressing the right problem.
Perhaps your client asks you to make a better kettle. Do they really want a better kettle, or nicer coffee? Maybe you don't need to build them a kettle at all, and instead just take them to the café round the corner.
Why do you want to avoid satisficing? It is necessary for survival.

Explaining refactoring [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 9 years ago.
Improve this question
Question
My question is how can you teach the methods and importance of tidying-up and refactoring code?
Background
I was recently working on a code review for a colleague. They had made some modifications to a long-gone colleagues work. During the new changes, my colleague had tried to refactor items but gave up as soon as they hit a crash or some other problem (rather than chasing the rabbit down the hole to find the root of the issue) and so reimplemented the problem code and built more on top of that. This left the code in a tangle of workarounds and magic numbers, so I sat down with them to go through refactoring it.
I tried to explain how I was identifying the places we could refactor and how each refactoring can often highlight new areas. For example, there were two variables that stored the same information - why? I guessed it was a workaround for a bigger issue so I took out one variable and chased the rabbit down the hole, discovering other problems as we went. This eventually led to finding a problem where we were looping over the same things several times. This was due in no small part to the use of arrays of magic number sizes that obfuscated what was being done - fixing the initial "double-variable" problem led to this discovery (and others).
As I went on this refactoring journey with my colleague, it was evident that she wasn't always able to grasp why we made certain changes and how we could be sure the new functionality matched the original, so I took the time to explain and prove each change by comparing with earlier versions and stepping through the changes on paper. I also explained, through examples, how to tell if a refactoring choice was a bad idea, when to choose comments instead of code changes, and how to select good variable names.
I felt that the process of sitting together to do this was worthwhile for both myself (I got to learn a bit more about how best to explain things to others) and my colleague (they got to understand more of our code and our coding practices) but, the experience led me to wonder if there was a better way to teach the refactoring process.
...and finally...
I understand that what does or does not need refactoring, and how to refactor it are very subjective so I want to steer clear of that discussion, but I am interested to learn how others would tackle the challenge of teaching this important skill, and if others here have had similar experiences and what they learned from them (either as the teacher or the student).
Like most programming, refactoring skill comes with practice and experience. It would be nice to think it can be taught, but it has to be learned - and there is a significant difference in the amount of learning that can be accomplished in different environments.
To answer your question, you can teach refactoring methods and good design in a pedagogical fashion, and that's fine. But, ultimately, you and I both know attaining a certain level is only through long hard experience.
I am not 100% to understand your question but I think you can refer yourself to Code Smell that need to be refactored.It contain a lot of example that you could show to other.
Here is a list of when refactoring should be used (list of code smell)
If you haven't read it, Martin Fowler has an excellent book on the subject called Refactoring: Improving the Design of Existing Code. He goes into substantial detail about how and why a specific piece of code should be refactored.
I hesitated to even mention it for fear that knowledge of this book is assumed by someone asking about refactoring, and that you would think, "Duh, I meant besides the Fowler book." But what the hey, there you go. :-)
You don't mention tests. To 'prove' that a refactoring does not break the existing functionality you need to either have existing tests or write tests before doing the refactoring.
Pair Programming seems to be the best way for me to get this across. This way, as we're working on real, production code, and we both encounter some code that doesn't smell right, we tackle a code refactoring together. The pair acts as the driver's conscience saying to do the right thing instead of the quick fix, and in turn, they both learn what good code looks like in the process.
Refactoring can be an art, and just takes practice. The more you do it, the better you get at it. Keep studying the methods described in Martin Fowler's Ractoring book, and use your tools (Resharper for Visual Studio folk)
One simple way to conceive of refactoring is right there in the name -- it's just like when you factor a common variable out of an equation:
xy + xz
becomes
x(y + z)
The x has been factored out. Refactoring code is the same thing, in that you're finding duplicate code or logic and factoring it out.
It sounds like your approach is a very good one. At the end of the process, you showed how you were able to uncover and fix a lot of problems. For educational purposes, it could then be interesting to invent a new change/enhancement/fix. You could then ask your mentoree how they would enact that change with the old a new codebase. Hopefully they'll see that it's much easier to make the new change with the refactored code (or how doing more refactoring would be the easiest way to prepare for the hypothetical change).
I see a couple of different ways you could try to teach refactoring:
Given textbook-like examples. A downside here is that you may have contrived or simplistic examples where why refactoring is useful doesn't necessarily shine through as well as in other cases.
Refactoring existing code. In this case you could take existing legacy code that you'd clean up, or your own code in development and show the before and after doing various bits to see how much better the after is, in terms of readability and ease of maintanence. This may be a better exercise to do as this is live code being improved and enhanced to some extent.
It isn't something that someone can pick up instantly, it takes time, practice, effort and patience as some refactorings may be done for personal preference rather than because the code runs optimally one way or another.
Teaching someone to refactor when they aren't a natural is a tough job. In my experience your best bet is to sit down with them in an office and refactor some code. While you are doing this keep up a "stream of consciousness" dialog. Talk about what you see, why the code doesn't smell right, options to refactor to, etc. Also you should make sure they're doing the same thing. The most important thing is to impart why, not how, to change the code. Any decent programmer can make a change and have it work, but it takes skill and experience to be able to state why the new solution is better than the previous.