5 ms·
I have worked for 3 years on a project where it took a whole week to get the code compiled, signed by an external company and deployed to the device so that I c
by lmilcin 5y ago
I have worked for 3 years on a project where it took a whole week to get the code compiled, signed by an external company and deployed to the device so that I could see the results.
I just learned to work without compiling for a long time. Over time my productivity increased and the number of bugs fell dramatically.
Working this way requires you to really think about what you are doing, which is always a good idea.
This was over a decade ago and now I work mostly on Java backends and I am happy that I typically spend days or even weeks without ever compiling the code and that it usually works the first time I run it.
I can't think how I could get back. It looks really strange to me to observe other developers constantly compiling and running their code just to see if it works. It kinda looks as if they did not exactly understand what they are doing because if they did, they would be confident the implementation works.
The only time when I actually run a lot of compile/execute iterations is when I actually don't know how something works. I typically do this to learn, and I typically use a separate toy project for this.
- random_kris 5y agoI am one of those devs that is always compiling and checking if their program is working. I am mainly working with java and still doing this. Less so than when working with JavaScript. But please teach me your ways hahha
- lmilcin 5y agoStart by understanding that this compile/run process is a crutch. Rather than use your knowledge, experience and intelligence to predict if it works you resign yourself to just waiting to see. This is a problem for many reasons. One is that this may help you get something working, but with lack of deep understanding the outcome will likely be subpar if only because not all problems that you could have predicted will show themselves on execution. Another is that it basically shrinks the part of brain that is necessary for understanding and predicting behavior of your code (figuratively). Sort of like driving with GPS makes me helpless without it. Try to write larger stretches of code without compilation. Try to focus on modularizing your application so that you can reason about modules separately. This is always a good idea, but it is even more important when you need to be able to predict how something works without trying it. When you have finally compiled your code and it failed, do not immediately go to fix the problem. Try to spend a moment to learn from the failure and improve your process so that you minimize chance of this happening in the future. Ask yourself, what you could have done to prevent this problem from happening? Could you have specified some function or module better? Could you have simplified your code to be able to better reason about it? Would it help if you have spent a bit more time getting acquainted with this internal or external library before you decided to use it? From my experience, most of this comes down to following things: - defining your modules and APIs correctly -- badly defined modules make it difficult to predict the behavior, - finding simple solutions to problems -- complex solutions tend to make it difficult to predict behavior, - using only tools you understand, - only interacting with existing code after you have understood how it works (I typically at least look over the code that I plan to use), - thinking hygiene (make sure you base your work on hard facts and not beliefs), - refactoring, refactoring, refactoring -- first solution to the problem is rarely optimal. I write something that works and then immediately keep refactoring it removing any unnecessary complexity until I am satisfied. Don't leave refactoring for later -- when you have just written a piece of code it is easiest to change it. - as much as possible, writing your code in a way that it is not even allowed to produce wrong result. This is very large topic so I won't explain. There is a lot of techniques that you can research.
- random_kris 5y agoDo you think there is a time and place where it is more sensible to just go by trial and error. For example when I am interacting with a codebase for the first time and I want to implement something I just keep bashing and throwing shit at the wall untill something sticks. After that I start working more in line of what you described.
- lmilcin 5y agoHow exactly you arrive at understanding the codebase is not as important. Just make sure you keep actual development separate from learning the tool if you care for your results and especially reliability. Now, I use various ways to learn the tools and codebase. Running PoC for my idea or maintaining separate toy project helps me with maintaining hygiene. For example, for the past year I have been spending a lot of time learning reactive programming with RxJava and Reactor. I have created a dozen small projects illustrating various ideas for making reactive APIs, processing pipelines, separating business logic from infrastructure, composing reactive modules, etc. I did this with aim of purposeful learning rather than writing production code, even though some of these in the end migrated to be part of production codebase. I am now at a level where I can, again, write large swaths of modules, libraries but now using reactive paradigm, with a very good chance of it working correctly, which for me validates that I more or less understand what is going on.
- ransom_rs 5y agoIn case anyone else does this and is new to Rust - you can use `cargo check` to type check/borrow check/everything else without doing any codegen
- lmilcin 5y agoThis thread is no longer with regards to Rust or checking whether the code compiles or not. It is about how you can work with compilation times that are longer than a coffee break.
- nine_k 5y agoOften you can be certain that you know what tp expect from your own code, but not from dependencies or external systems. So checking that your assumptions about them are right is a major reason to run and rerun your code.
- lmilcin 5y agoThat is good reason to minimize amount of dependencies and only use the ones you know and can reason about. It is also part of what I do to help me reason about code before I execute it. As I mentioned, if I don't understand a dependency or external system I make separate toy project where I can rapidly experiment and learn. Think of it as having fun in a aircraft simulator. You play with it so that you are prepared to fly the actual plane. Also checking your assumptions by trying to see if the code works is a problem in itself. A lot of these broken assumptions will not break your code immediately but maybe sometime later. Maybe when your application is under load or maybe when clock on the server is moved back by an hour or maybe when the connection breaks in a certain way. Base your work on knowing how something works and not assuming. Best way to limit the risk of your application failing due to broken assumption is to limit your reliance on assumptions in the first place.
- marcosdumay 5y agoI used to use approach, but the new heavily typed languages bring a lot of really nice tools that you only get to use at compile time. Specifically in Rust, you can use the language to guide you through things like refactoring, thread synchronization, correctness verification and a lot of other things. But you have to run the compiler.
- lmilcin 5y agoI don't write production code in Rust (though I learn for my embedded hobby). But you can say the same for Java. IntelliJ IDEA internally does equivalent of compilation and tells me exactly where my code would fail to compile. So in a sense I am not strictly practicing my approach, but I also don't see reason to do so if the tools are reliably giving me hints when I made mistake writing something that will not compile.
- SV_BubbleTime 5y agoHow do you like embedded Rust? I’m looking forward to someone making a legit IDE/suite with support, no indication of it yet but I assume some day!
- lmilcin 5y agoI mainly work with STM32 Cortex-M3 MCUs (again, these are my personal projects). Rust, well, "works". But there is still a bunch of issues so I keep developing using C until I get the kinks ironed out.
- steveklabnik 5y agoIt's working really well for us at Oxide. I even do it on Windows :)
- slunk 5y ago> So in a sense I am not strictly practicing my approach Developing in an IDE that compiles almost continuously is about as far from the development philosophy you're advocating for here as one could get :P
- throwawayboise 5y agoFirst job was in a mainframe environment, compiles were pretty quick but the job queue was so big and developer compiles were low enough priority that it could take hours of wall clock time to turn around. I don't remember the specifics but while watching the job queue on the terminal screen I discovered that the job priority was editable. So I bumped it up, my compile job ran, and I was happy. I only did this a few times before I got a lecture from the system operations guys that was quite explicit that I should never do this again. Yes, you figure out how to run code mentally, how to check carefully for typos and syntax errors, etc. No Intellisense then either, that's another modern crutch.
- hinkley 5y agoMy theory for Java is that it was frog boiling turned cargo culting. Comparatively speaking Java compilation was very fast at the beginning, so for instance Red-Green-Refactor (RGR) works pretty well. There's a parallel to other creative jobs where sometimes shuffling around the things you already have reveals a pattern that leads to a breakthrough. But there are other feedback loops that, with J2EE in particular, the cycle times started to creep up, and up, and at some point if you haven't stopped and looked at what you're doing you don't see how crazy things have gotten. RGR still has a place there because you are typically not recompiling everything and you aren't spooling up the application to run unit tests. But making one line changes to see how a page loads is just bonkers amounts of busy work. One of the bad dynamics is that people more like you also tend to memorize the code, which is both bad for new hires (circular logic does not reveal itself when you introduce one assertion at at time, but does when you get hit with all of them at once), and also incentivizes you push back on refactoring. Because those damned smartasses keep moving things around and they were Just Fine where they were. If that happens you have cemented the entire codebase and anything that is really wrong with it is going to stay wrong until someone proposes a rewrite. And having learned the wrong lessons the first time, we repeat them again in the second iteration.