There is a quote from Louis Nizer that applies here:
"He who works with his hands is a laborer. He who works with his hands and his head is a craftsman. He who works with his hands and his head and his heart is an artist."
Its that last part that is hard to bridge for a lot of engineers. The thing that did it for me was sitting through a LOT of formal usability studies. Seeing folks actually use an application you made, where they make mistakes, get stuck, will change your relationship with your code. Even if you work purely on the back end building APIs, you have customers (other developers in this case).
Focus on the what the code does, and why someone would use it, care about your customer... the how only matters to your fellow engineer, and if it is that bad they are going to give you grief for it and you can fix it.
I started my career in a small software company that wrote Mac software (in the System 6.5, System 7 days). We had no dedicated support staff, so support calls were either handled by the sales staff or development. Talking directly to customers, hearing where they were having trouble, and learning what they wanted to do, was probably the single most valuable experience in my career. My first thought with any work became "How can I completely eliminate the possibility that I will end up having to support this?"
Of course, this backfired spectacularly a few years later at a different company, when a customer stopped paying a lucrative support contract because the software always "just works". I have decidedly mixed feelings about that!
That isn't such a problem nowadays as you could move the business model from outright purchase plus support to a software as a service model with monthly fees and minimal support costs.
I see Python3 as poor engineering. There are no technical reasons why you can't run bytecode from both 2 and 3 together. Various JVMs and the CLR solved this problem. They created their own problem by refusing to built or maintain a comprehensive solution. As well, there's nothing in Python3 that didn't already exist in the Python2 ecosystem or was trivial to add to Python2 (backport or otherwise). Thus many of us see CPython3 as technical churn rather than technical innovation.
I share your sentiment about having 1 version of Python but it's not the users fault. It's the core dev team's and Guido's.
> When I try to build something new, I find myself instantly criticizing my technique, to the point of paralysis. This function is hard to test; this object's dependencies need to be injected rather than initialized internally; that module needs an integration test; and so on and so forth. Even when writing spike or proof of concept code, I find myself revisiting the same lines over and over again, looking for the best, most natural expression of the ideas it contains -- obsessing, like Catt said, over my own construct, rather than on the thing my code does.
I used to be like this for the first few years of programming. And I knew a guy at my last job who was exactly like this. The thing that helped me, when I felt the indecision paralysis come on, is to just do something and accept that it may be wrong. You often don't know the best decision in the first place because you lack experience. Doing it the right way by accident, or making the mistake of picking the wrong way helps get you that experience. Be deliberate about always doing something, and over time the paralysis will get less and less as you gain more experience.
I'm naturally a perfectionist, so I fall into this trap often, though I've gotten better over time. I rely on a few simple tricks (ugh, the buzzfeed headline practically writes itself):
1. If I'm stuck and can't decide which path to take, it's usually because I don't have enough data to tell which path is better. The fastest way to get that data is to pick one path arbitrarily and start walking down it. Pretty soon, it will be become obvious if it's the wrong path.
2. One of my favorite things about code is that it's infinitely malleable. Especially thanks to the magic of Git, I can undo any change. Nothing is permanent which means no decision is carved in stone. Deciding isn't deciding what to do forever, it's deciding what to do for now.
3. Sometimes I get stuck trying to do a depth-first traversal of the fractal tree of all possible implications of the program. Going depth-first down every single edge case and rathole is not an efficient way to get something up and running.
You really want to go breadth-first or best-first instead. To do that, you need to leave markers in your code of which branches remain to be explored. Those are TODO comments. So instead of falling into a rathole and not making progress on the thing that's at the forefront of my mind right now, I just leave a TODO, "Figure out what to do here if the ___ doesn't ___."
TODOs are great because they help my current velocity by not getting sidetracked and my future velocity by giving me something to pick up on when I finish something else. I pretty frequently search my code for TODO and grab one that sounds fun.
I have recently started to just commit to one path as well. It reminds me a lot of writing papers for my classes when I was in school. Staring at a blank page is hard and staring a blank IDE can be even harder. I find that just starting with the smallest thing you know is your first step, be it a simple API call or even just spitting out "Hello World", really helps and after you start you can keep iterating on that base. Over coming the static friction seems to be a lot harder than keeping momentum.
Thank you for the reminder - you've made me realise I've been trying to implement a whole system at once when I really should just do the proof of concept and go from there (the only problem with that is that prototypes have this funny way of making it into production when you least expect it)
I frequently use TODOs and I don't get crazy if I don't go back and do all the TODOs. Some seem important at the time and become less so with age. Others become more important.
I feel like this leads down a dangerous path of no signal-to-noise ratio and destroys your hope of finding relevant TODOs. Better to, as part of revisiting them, rewrite the comment to explain the de facto behaviour for yourself (and others) in future. If you're not going to do them, anyhow.
You make good points. I don't use them so much as to bother me. I code for a team size of one (me) so that gives me liberties that I might not take elsewhere.
No. It has to be clean, correct, and come with full unit test coverage the first time. You have until the next sprint to implement it. Your workspace is a Macintosh at a long desk where you'll be working shoulder to shoulder with other devs working on other projects. If you can't manage even that, you're just not a good fit for our company; we expected more of an engineer of your experience level.
Awesome. I interviewed at one of these once, I knew I wasn't going to get it when I saw the massive imacs and the square glasses... plus the guy couldn't explain what it was they did at all.
What's amazing to me is that devs/engineers are acutely in demand. It's odd that, given this, so many organizations get away with environments that are overtly hostile.
Depends on your industry and where you work obviously. But I have a strict "that will do" policy. If it looks like it might work, that will do.
It won't' be well engineered, it will be buggy. But the project will be completed and released. If it makes some sales and looks like it has some traction, then I go back and visit the many (many) //todo - clean this up and refactor everything out.
Usually after a while of adding more features, hacking out nasty design decisions the best way on how to do it comes to the fore naturally.
I agree with this philosophy as well. If is a project or program that will be worked on more as time progresses, typically it refactors itself after the programmer has a better grasp of the big picture. Often the bigger picture can only be grasped after there is some momentum with the project. I'd say this works 90% of the time, where the other 10% needs more upfront design and research done before any real work is started.
It's rapid prototyping. It might just happen that the prototype is good enough to sell, but once you have a basis, comparisons can begin. If the prototype doesn't have to act as the real product, just a skeleton, it's not so hard to change the "bones" if something isn't working properly.
If the prototype is quickly made, it could even count as part of that upfront design process.
I like my people to do more than prototype for this kind of work. It's probably a semantics argument, but we prototype as part of design and intend for it to be trashed/rewritten, whereas what I was speaking to above is real development work that will be used, definitely not polished but 'works' enough to keep moving forward.
That often means "getting the bones" right, but occasionally cutting corners to get stuff done. If your focus is having a good product, which frankly it most of the time should be, then done is better than perfect.
In that line of thinking, I would have to say it's more like dough. At the beginning good dough is very wet and sticky. If you are not decisive with your actions it will stick to your hands, your board, your table, your hair... As you work with it, it creates a workable ball that is dry and elastic. You can shape it with ease, it stretches paper thin without breaking, it rises high and light. The more skilful you are, the faster you can go from gloop that threatens to devour the world to something that is smooth as silk and almost feels alive. Those with little skill and experience never actually get there. They believe that beautiful well formed dough is a myth. They compensate by adding more and more flour so that the dough doesn't stick to their hands, in the end baking literal bricks. They pretend that the resulting bread is good.
I had this tendency too, and I've found that it helps to explicitly declare the first part of your process as "start at this new thing and suck at it." Firstly, because in order to suck at something, you're doing it, however badly. Secondly, because once you have some results, however bad, you can improve.
It's exactly like randomly initializing a neural net before starting with your training data. The results from the random weights will be garbage but that doesn't mean they're not useful.
Well said. IMHO, this is the core of the issue and the thing that has helped me both move on and improve. You have to be ok writing crappy code because, in lieue of experience or someone to (on the spot) help you, its the only way forward. As long as you're professional about learning and refactoring, the best you can do is keep moving, keep learning, keep refactoring. Then eventually, help move others through that gauntlet more quickly.
I think it's really liberating when you realize that the single most important thing is making it work.
Make it work, and don't succumb to the temptation to worry about what other devs think of your code. The subconscious dialogue that results from that is paralyzing. You can rewrite code n number of times and always believe that n+1 will be better (and it may be).
But, the funny thing is that the eventuality that would objectively make the code better is generally some potential future requirement that is imagined (whether functional or performance). This dictates infintely flexible design and the obsesive hunt for looser coupling. In practice, however, the eventuality seldom comes to pass. This is where the YAGNI principle has some value. Again, make it work.
The thing that helped me, when I felt the indecision paralysis come on, is to just do something and accept that it may be wrong. You often don't know the best decision in the first place because you lack experience. Doing it the right way by accident, or making the mistake of picking the wrong way helps get you that experience. Be deliberate about always doing something, and over time the paralysis will get less and less as you gain more experience.
Well-stated -- and (at the risk of over-complimenting), very close to the absolute zen of self-driven learning.
Yes, this. I'm self taught -- half the time I'm coding, I don't even know what a "good" approach should be. So I just get started on something, since there's no perfectionist ideal I'm visualizing that I need to hit.
The ironic part is that I face this exact problem with the thing I am formally trained in -- writing. The blank page paralyzes me in a way blank vim never does.
That's the thing - we often don't realize what was wrong (or, occasionally, what was actually awesome) about what we're trying to create until after we've put it down not just on paper (or in code), but in front of other people.
It's absolutely intrinsic to the nature of the process. And the best way to virtually guarantee that you won't be ever get to find out whether your idea was good or bad, let alone truly awesome, is... insisting on perfection before it ever gets out the gate.
The thing that helped me out of this, was seeing writing code like forging a sword, where you repeatedly heat up the metal, hammer it into shape and then cool it down again. (note: IANASwordSmith)
This works because heating up the metal makes it easier for it to arrange itself into a more optimal configuration and then you hammer it into shape and cool it down again to preserve the awesomeness you already reached. Then you repeat that process a thousand times until you have a katana that can cut through steel.
So, don't worry about just implementing a feature very roughly and breaking apart old structures you already put into place, you're just "heating up the metal". To see how everything should work and what it should behave like (i.e. "hammering it into shape"). As long as you then do the clean up/refactoring and put everything in the right place and such, i.e. "cooling it down again", you'll end up with awesome code that's robust and expresses what should be done very well.
So, in a way, imagine you're a smith at the forge, forging your code like a Hatori Hanzo sword, which is also a nice methapor, I think (with the difference, that your code's purpose is hopefully not cutting peoples heads of!).:)
I feel like my experience is the opposite of this.
I've never understood something until it stood between me and building what I needed to build.
This approach has been great professionally, but lately I'm becoming more interested in theory intensive fields and struggling to find resources that teach from the perspective of someone who wants to build something that requires the knowledge involved, rather than someone who just wants that knowledge.
I've been just like this - without the context of a problem to solve, theoretical things just don't click for me. Regex was a mystery and impossible to memorize until I had to write a matcher for a class, and I haven't forgotten since. Similarly, I never get stuck at work, because everything I learn has a problem behind it, but as soon as I go home and try to teach myself something for fun I derp out immediately.
What worked for me was finding a civic problem that was annoying just enough to want to fix, no matter how large it is. You learn a lot from it, but it also gives you a chance to get more involved in civics, particularly from the projects that stem off. Since the motivation is in helping your community out, it gives a little extra motivation and joy. The projects kind of build on themselves since the rabbit holes go so deep.
For example, I'm working on plotting parking tickets in Chicago. Tons of FOIA, lots of data analysis, sanitizing, python, GIS, government induced hair pullings, gnu cli tools, civic meetups, web scraping, etc. Finished this[0] last night using 730k parking tickets after a LOT of cleanup with python. There's no way in hell I would've been able to do this a year ago without stepping into something so deep.
Are you located in Chicago? If so, sounds like your project would fit in perfectly at ChiHackNight: http://chihacknight.org/
I'm guessing that you are already familiar with ChiHackNight, but if not I recommend checking it out.
Yep, I've been there a few times. Meant to go there today, actually. Cool crowd, but I have some general criticisms of the way they do things. I'm almost to the point of thinking that their work is an overall detriment to the city, since there's a strong tendency towards group thought rather than individual exploration. Their workshops also get nothing done since the barrier for entry is so low that they're so busy answering pretty basic questions.
They actually brought in a hired gun political data scientist who does research on his employer's opposition to help paint a bad picture of opposition. It was seriously presented in a positive light and everything! Hell, when I asked him his thoughts on FOIA, he basically completely shrugged me off and called it useless, despite things like that graph, which was created through FOIA data.
Chicago's head data guy is there almost every time, working on workshops, which is pretty neat. Incredibly interesting guy. But, I have a hard time finding legitimacy in his presence when Chicago's only analysis of parking ticket data (something ChiHackNight would love to work with) is this [0]. Received through FOIA after specifically asking for any analysis they've done on parking tickets... You'd think the head of data would have addressed that.
It all just feels very Feel Good.
Once I get this project to a certain point, I'll probably head back there and show it off and ask if someone else wants to take it over. Eventually, starting one of my own group would be nice, but I'd like to have something under my belt beforehand to help with legitimacy.
Yeah, this is my problem as well. I have a really hard time coming up with ideas for a good side project, and then when I do, half the time I find out someone already implemented something like that and it feels like I'm just pointlessly reinventing the wheel.
I think I need to do a better job of reminding myself that it's not pointless as long as I learn something.
Another reason it's not pointless is that diversity breeds resilience. Perhaps your implementation will sidestep some issue the pre-existing ones have or perhaps it will just appeal more to some people's workflow (likely yours at the very least!)
I'm always worried that it's not great for me professionally. Because the "cool kids" are always off learning the hot new thing, and I can do what I need to in the "old" thing, and so I don't learn the hot new thing.
Aren't I, as an engineer, supposed to be constantly entranced by the bleeding edge of technology? Whether it's the latest lisp Dialect, the latest functional programming language, the latest NoSQL database, or whatever the latest is?
Granted the nature of my work is such that I wind up using tons of new technologies every new year, but I don't go out and experiment with them with no particular use in mind.
I'm also a very practical learner. It's hard for me to pick up anything (whether it's a language, technique or a theory) without applying it. So to pick up new technologies I constantly cycle them into new projects.
I can, but I won't build in the hot new thing for the sake of the hot new thing alone.
What that tends to mean is that when I'm looking for a new job, my skills at old company are in old thing, while everyone is excited about hot new thing. This is typically most obvious with javascript libraries.
I'm mixed on this myself. The way I look at it is that since I am more focused on results, I'm always looking for new tools that will do more of the work for me.
That said, I get what you're saying. Often it's clear the new fad doesn't provide much utility. In those cases it's like waiting for a cold to be over.
This resonates with me. A lot of my tools update, and I eventually find good uses for the new/changed capabilities, but unless I have a particular use in mind, or unless it provides a concrete benefit, it's hard to chase after the new-shiny.
I'm often curious about the theory, or at least the "How do I do X?", bits of programming. What helps me is picking something I'm curious about, and then figuring out how to be curious about a smaller piece of it.
Lately I've been curious about how I could go about building a web framework in Elixir. I started off buy spending this past Sunday digging into how to open sockets/ports, and send requests from my browser, and reply to them from the Elixir command line REPL.
I am like this too. For me, I find that using a curriculum as a means to an end does three things:
1. Applying your knowledge forces you to confront the gaps or uncertainties in your understanding that you would normally overlook.
2. Allows you to interleave different the topic with related subjects, which gives you a broader or more fundamental understanding of the topic.
3. Attaches an immediate utility value to your study regime, which serves as a better motivator and means to identify when to study hard and go deep, and when to gloss over.
I agree! I have a hard time focusing on something that is purely academic unless said academic thing seems to have a property I want to explore on my own or use to build something.
I got several C's in calculus because I was too busy messing with slightly different calculus instead of doing the problem sets for the tests.
I regret nothing, but I wish I could learn the same way most people seem to be able to sometimes.
Don't wish that, you have personalised learning for internal goals over grades. You will continue learning for your whole lifetime. While some others will need approval incentives just to pick up a book.
If you have the patience, a few deep Google/Wikipedia sessions can do wonders, followed by a subscription to Pluralsight to learn whatever hard skills you might need. In my case, I'm backfilling my linear algebra / set theory / statistics learning with Coursera and Wikipedia while learning R and some NN stuff with Pluralsight. I'm trying to build something specific with it (facial recognition) so I'm also learning about that in depth (mostly through Google -> blogs/WP/articles/products/open-source). Just trying to fully comprehend the READMEs and docs of projects that look useful has given me a lot of leads.
FWIW all this math stuff a) makes way more sense with some FP knowledge, and b) is not all that hard to understand in the context of a project.
Finally, for extra immersion, start reading Data Tau (the data science version of HN). Just pick out stuff that's related to what you're working on, and then try to understand a whole article or something. That's what I did with HN and I grew exponentially as a programmer because of it.
Another thing I run in to a lot is people saying "I know how to program, but I don't know what to build." There is an amount of creativity involved with programminng.
It's like learning how to physically manipulate a guitar and play notes, but saying "I don't know what to play." That happens a lot too, but musicians have the repetoire of other composers to play if they do not want to write their own music (many don't). With programming, recoding something is called reinventing the wheel and that's frowned upon.
Ok, sometimes the analogies are forced, but I hope you get it! It's kind of interesting though, because in order to progress we have to build something new, or build on top of what we have, so the technology is forced to evolve. Music can repeat over and over and people don't get tired of it and you could argue pop music is working against the evolution of music.
Learning the programming art is like learning any other art. You first learn the rules (and even more importantly the REASON behind the rules). You then build the discipline of applying the rules. And finally through experience you learn where some of the rules just don't apply.
The usual progression is something like:
1. Build your first major project as senior engineer. You make something that works, but is brittle and soon becomes difficult to work with.
2. Build your second major project. This time, you adhere to ALL established best practices. The end product is difficult to configure because you've gone too far in flexibility, and a major pain to maintain because the codebase is 3x larger than it needed to be, and filled to the brim with boilerplate code. You also resist changes that threaten the precious architecture. Everything's perfectly isolated and testable, though!
3. Build your third major project with the minimum needed to get it to work for your client, keeping a few of the best practices to keep it mostly flexible enough for changing requirements. It will eventually grow in unhealthy ways as requirements shift beyond fundamental architectural assumptions, but you already knew this going in.
4. Make the mistake of doing a "2.0" rewrite of your major project. Vow never to do it again.
I think there is a lot of truth here. Recently I had to work with some old code of mine that I wrote ten years ago as a (Physics) student, and looking at the code I realized that while it was a bit ugly and "unconventional" it worked quite well. If I would start the same project today (after five years of intense software dev experience) I think I would be at a much higher risk of "writer's block", simply because I think of so many aspects of the code (testing, deployment, architecture, documentation, language, tooling, framework) that were just unknown to me at the time and which therefore did not distract me. So in a sense, ignorance really is a bliss.
Here's the code in case you're interested, it's for simulating superconducting circuits:
c2 is a great wiki. Start googling languages and programming phrases with site:c2.com at beginning. You'll find some good stuff. Unfortunately, its commenting got shut down shortly after I discovered it. I think I read all the debates and stuff. Too many haha.
Note: The debates over LISP, OOP, Cleanroom, Smalltalk, and so on are all especially interesting.
Unfortunately, his current employer chose a different order: 3, 1, 2. Sometimes they drop 1, 2, or 3 separately or in groups at random. Gotten much better at 2 and 3, though.
I can relate to this. You see it in a lot of domains. I see two concepts that apply: Practice/Performance and Generation/Synthesis.
To be a musician you must practice, but you must also perform. These are two different modes. When practicing, the goal is to improve a specific technical skill. You don't concern yourself with expression at all. You will repeat the same passages over and over and many exercises sound really terrible. When you perform, you put your trust in your training and you access an intuitive part of yourself to add feeling and nuance to your playing.
In design thinking, it is common to split activities into generation and synthesis. When generating, you recklessly explore possiblities, tossing them out, following blind alleys, making weird connections. Synthesis is the process of evaluating the generated ideas against some framework, such as goals or known models, finding patterns, simplifying and making coherent.
We need all of it: practice, performance, generation and synthesis. Experience brings a sense of when each mode is appropriate or needed. Being explicit about which mode you are working in removes the stress from attempting to practice while you are generating or similar dissonant mixes.
More concretely, a user-centered process has brought a lot of this mental framework to development for me. Step one is never setting up a test harness, it's understanding the user and their goals, even if the user is yourself.
Everything else flows much more easily from this starting point. You can base your decisions on how they will affect the user instead of on "best" practices that may not have the best outcome in your situation. Things like precision, speed, fidelity, automation, complexity, stability, even whether or not to build something--all involve trade offs that affect the user in different ways. You can experiment more freely knowing that you will evaluate your experiments in terms of their utility for the user.
The art is in applying this left-brain-right-brain dance to trace a path through all the complexity on behalf of the user.
You just a need priority list. If you think something needs to be fixed, add it to the list. Choose the next task with the highest priority when you are done with the current one. At least you will know why you didn't fix something. It would be most likely be because there are only so many hours in a day, and your skill does not change overnight, despite obsessing over it.
There's a couple modes of engineering mindsets I'm conscious of.
1) Being careful of every change and addition I make. Trying to figure out and predict the effects, scalability, and maintainability of the code I produce. I find that most engineering positions are looking for this, as most employers already have an existing production code base and would not like wild things like crashes and service disruptions to happen to their audience.
2) Occasionally, I get to start on something completely new. Not new as in just a blank page, but new as in blank project, or even blank idea. As exciting as this sounds, over 90% of the time, the idea will die as there is some undiscovered flaw or expectation almost always external to an exceptionally well thought out implementation. The only thing clear about this is the urgency of the deadline, and the failure associated with missing it (missed management expectations, no demo, no presentation... etc). Many know this as building a Minimum Viable Product. In this case, all rules go out the window. Choose expedient tools, create copious crap code and internal design, as long as it works OKish in the end. Having it violently done tomorrow as opposed to 3 days later, or a week later, or a month later, is key. If you're lucky and it limps along (not canned as uninteresting), just change hats and become the step (1) engineer.
Sounds like you desire some more experience with (2), but both types of people are needed. You, yourself, will become more valuable if you can put on both hats, but I wouldn't say that one hat is absolutely better than the other.
Where you see your greatest weakness, I see your great strength.
I'm good at building stuff, but I'm not a great engineer (I'm ok, but others on my team are way better).
Not to say I don't have my strengths. I'm good at figuring out what to build and the general architecture of how to get it done quickly and working well.
But when it really comes time to scale and scale big, you don't want me coding. You want me looking at the next features etc. etc.
If you love getting into the nitty-gritty of high quality beautifully considered easy to work with code, why do you feel you should focus on 'building stuff'?
Personally, I think focusing on your strength (not to completely ignore building stuff) can be a huge benefit.
Meanwhile, I've seen way too much code from people who're good at building things, but not engineering. And lost countless nights to keeping these rickety structures alive long enough that we could fix the most egregious issues.
Sure, build something, anything, to show it can be done. THEN MAKE SURE ITS ACTUALLY STABLE.
And then realize that building stuff, and understanding how to build it well, both matter.
the critical self talk is normal. you should watch seth godin's talk "quieting the lizard brain" https://vimeo.com/5895898
i just had a similar conversation, but it dealt with music instead of code. this person felt they couldn't improvise/ create.
the problem isn't with their abilities, it's that they were taught to follow instructions - like the notes on sheet music. jazz musicians play off what they hear instead. however, they first internalized the rules and then forgot them.
you've already got the rules down - so the next step is to "forget" them.
a time constraint like going to a hackathon is a good place to start. you're pushing yourself to create in a short amount of time.
here, you'll focus on shipping...drowning out the critical voice in your head.
it's much like a muscle. the more you build and struggle through, the stronger you'll get.
Very much this. If you force yourself to make lots of things at a fast pace, whether by hackathon or something else, you will eventually get over your hesitations, and you'll find yourself speeding up and building better things too.
God I wish the rest of my team would read this... I feel like they're more concerned with what stupid monad to use or how to create a really deeply nested class hierarchy than making features and bug fixes that deliver value to people who use the software
That makes too much sense! Honestly though, the fact that that seemingly obvious suggestion is actually quite difficult means there's something wrong with me or our team culture... something to think about I guess.
One thing that really threw me for a loop was back when I started learning about TDD. I tried to apply it to literally everything I coded. This caused a lot of paralysis because I was worried about whether I was testing the right way. Over time I came to a compromise. Basically, if I have a good understanding of the design and what I want to build and I know it is going into Production I use TDD. If I'm not entirely sure what I am building or I'm exploring an idea or spiking/prototyping something then I just write the code with little regard for things like speed or design patterns.
Good advice! If we really cared about the systems we create and the effect they have on the world then the language it is programmed in and the implementation of that system would only be one part of the process. The means of effective reasoning about the design of software systems is formal. However it seems to be outside the scope of any introduction to computer science or programming course.
To quote Friedrich Bauer:
"Software engineering is the part of computer science which is too difficult for the computer scientist."
Meh. It should meet the requirements. And at any rate the next dev to work on your code will declare that it stinks and needs to be refactored at best or completely rewritten.
A lot of times as engineers we don't have to build anything. We only have to fix, maintain, or tweak. Or maybe build just a very small piece of something. So it's perfectly OK for most of us to suck at building stuff. But on a team it's important someone fill that role. But most of us shouldn't or it would be chaos.
That's a good point. Also, in the process of solving one problem you may discover a more interesting, more relevant, more general, or more universal problem you could be solving instead.
I like this post because it captures some way in which my perspective has changed over time. Engineering was something I saw as a way to perhaps "cheat" at product problems because if I made a good enough/fast enough/automated enough/generic enough solution, I would be able to iterate on it really fast and so somehow come out ahead of people who went directly towards the simple solution. This mentality was clearly inspired by years of homework being a task that would never go away and that I desperately wanted to get out of my life as fast as possible in the way that consumer products advertise their elimination of household tasks - ergo my goal as a student was to wish I could automate away all aspects of my studies. I would look for any kind of secret trick or forgotten technique that would get me closer to that goal at minimum effort. All the while I would build very little that was finished and get lost in maximizing my use of silver-bullet abstraction.
I've eventually come around to flipping this idea on its head, though. If I design not just some kind of product or solution, but a whole process, starting basically with how I want to run my life and then drilling into specific details from there, the technical knowledge stands on more even ground with other forms of knowledge, and with seeing life itself in a more precious sense.
With that mindset, good scheduling of every day as an end in itself grows vastly more important, and abstraction-for-its-own-sake falls away: All programming problems start by assuming they are solved first with "code that looks like breadboard wiring" [0] and then working up the abstraction ladder from there. Automating the technical parts of the solution won't guarantee that it's right in any other way, but it will ease the pain of changing the specification. Acknowledging that the problem is messy, that breadboard coding is messy, and that I won't know how to solve everything immediately and cannot depend on a silver bullet, all constitute crucial first steps.
Now I always look for really basic groundwork to be laid out early on - typically, transforming the breadboard code into something that uses a new data structure, or generating the code flow from a stack or a list or a tree - and that no shortcut is possible without compromising the ability of a potential future abstraction - that it just takes a lot of layers to get where I want to go. Breadboard code is assumed to be ideal until demonstrated otherwise, while "x in y lines" hype is to be avoided under the assumption that the solution is brittle and over-modeled towards the demo code. I cannot assume that my valuable production code will need x or work in y lines. I don't abstain from adding dependencies, but I will preference towards copy-paste-own when I find a reason to reuse code.
Makes people mad, but it's true. People who rest and reap profits orders of magnitude above those who work, due only to the fact that they hold capital, are leeches on society.
I see. And when those leeches lend capital for a new startup effort that otherwise wouldn't happen... allowing a business to form, a product to develop, an industry to blossom, on an accelerated timescale, what then? Would you still brand this role a parasite?
I realize that this sort of anticapitalist nonsense is currently fashionable in university, but the irony of it being spouted on ycombinator (which might have something to do with investors, after all) is really quite amusing.
> I see. And when those leeches lend capital for a new startup effort that otherwise wouldn't happen... allowing a business to form, a product to develop, an industry to blossom, on an accelerated timescale, what then? Would you still brand this role a parasite?
How is that qualitatively different from a medieval lord who chooses to permit peasants to work his fields for their survival, in exchange for growing wealthy off the fruits of their labor?
The rich graciously permitting the rest of us to share a small portion of their wealth, so that we can work to make them more wealth while incidentally keeping a bit for ourselves, is the basis for much of our society; but that doesn't mean there's no other way to do it, nor does it make them inherently virtuous.
(I'm not saying they're inherently monstrous, either. Many capitalists may be well-meaning and try to use their money for good, and that is laudable. But don't pretend that the mere fact of having and investing money makes one a hero.)
> I realize that this sort of anticapitalist nonsense is currently fashionable in university
It's been fashionable in every place and time where abusive capitalists have existed.
> but the irony of it being spouted on ycombinator (which might have something to do with investors, after all) is really quite amusing.
The header up there at the top of the page says "Hacker News". It's fashionable right now to imagine that every hacker yearns for a West Coast startup and loads of venture capital, but it's not actually true.
Just because a CEO spends their day making high-level decisions because they are literally delegating tasks to tens of thousands of people doesn't mean that they are "resting".
This is probably the best description of what we see of him that I have ever seen. Combine that with his verbal judo and one should not be shocked that he was successful.
"He who works with his hands is a laborer. He who works with his hands and his head is a craftsman. He who works with his hands and his head and his heart is an artist."
Its that last part that is hard to bridge for a lot of engineers. The thing that did it for me was sitting through a LOT of formal usability studies. Seeing folks actually use an application you made, where they make mistakes, get stuck, will change your relationship with your code. Even if you work purely on the back end building APIs, you have customers (other developers in this case).
Focus on the what the code does, and why someone would use it, care about your customer... the how only matters to your fellow engineer, and if it is that bad they are going to give you grief for it and you can fix it.