HNHacker News
TopNewBestAskShowJobs

cessor

321 karma · joined February 12, 2014

submissionscomments
cessor··on The use of `class` for things that should be simple free functions
Yes, why not have max and pow as objects?

`max` and `pow` can either run eagerly (as functions) or they can run lazily and allow for interesting lazy things. For example, if you put them into a lazy object graph, you could perform optimizing measures.

Check this out:

1/2 * 2/1 == 1

Would you actually calculate each intermediate result of that expression? Or would you just reduce the fraction? Should 1/2 be exectuted and yield 0.5 immediately, or could it be useful to have them hang around some more? FP vs. OOP is the difference of understanding / as "Please divide 1 by 2 now" vs "That IS a fraction; one half".

> There is no need to force every peg into a coalgebra hole.

True, but how awesome would it be if I did that anyway :D

Regarding `max` and `pow` as objects: Yegor Bugayenko argues for a similar thing in his book "Elegant Objects".

cessor··on The use of `class` for things that should be simple free functions
I am not sure I understand your differentiation of explicit and implicit state. I believe you refer to Objects that change their internal values over time; in that calling the same function twice yields different results. Of course, such objects can be a pain to use.

Objects are all about making state explicit. Constructors connect different primitive values to a higher order concept, goal or task and checks invariants; The object's class gives the primitives a type which IS a form of state. A Year(2005) could guarante that the integer is > 1970; an int can do that on its own. 'hello@example.com' is not just a string; it should be an Email address and modelling this with an explicit class communicates state: that string is not just any string (all of Shakespeare's work in mandarin in base64) but a specific kind of string (an Email address). The mere existence of a valid object then communicates state, as do all types. I'd argue: Objects are all about making state explicit.

Still, it is really easy to abuse objects and make state implicit as you described above. I would argue that getters and setters are plain wrong to begin with, but that is a nother topic.

For example, if you do `Wallet.pay(amount)`, Ideally, you should get a new instance of a Wallet with the reduced amount, instead of reducing the internal credit variable. For many, this seems to be the wrong kind of modelling though, because when immitating the real world, you don't copy-clone your wallet physically when tipping a waiter.

Objects can and should be created immutable, but then, sometimes working with state is fine. For example an iterator (calling `bookmark = Boomark(book); bookmark.next()` a hundred times gives different page each time).

Imagine OpenGL; you send a lot of data to your graphics card and then tell it what to do with that data. Sending data is quite expensive. During rendering, you tell the pipeline what buffer to bind and what to draw at a single point in time (i.e. a frame). This is easlily represented by objects that keep track of the state. Your object-graph just remembers what buffers are bound. I, too have seen tangled and messed up designs; but I would still argue that thinking in state (my change does not go away) is intuitive for many people. Why not model systems that work like this explicitly? Shoehorning this into stateless pipelines can be quite difficult.

The problem isn't functions or objects (thats just fancy pointer syntax really) but that noone has figured out how to modell processes that work on symbols that change over time properly.

We won't fix this issue here; let's agree that we all like our state as explicit as possible as to avoid surprises and relieve or working memory.

cessor··on The use of `class` for things that should be simple free functions
Reducing OOP to implementation detail features will yield poor results. The flexibility stems from an improved means of analysis in that types and entities can be identified more easily. By using classes and objects you're retaining flexibility because they can be interchanged; It's easy to create an object that pretends to be a function; it's harder to make a function retain state later.

The example is nice; it removes a lot of code but also removes the deferred execution aspect of the solution. Calling `countDominoTilings` will make it run in that instance; encapsulating the whole thing makes it able to pass it around and execute the potentially expensive `.count` method later. If applied properly, this can give you quite a lot of flexibility; for some memory and performance tradeoff; but that's the cost of abstraction.

Instead of looking for how FP and OOP are dissimilar, why not start looking for similarities instead? Objects are just higher order functions. Calling ctors is just partial function application.

cessor··on Windows package manager does not permit opting out of telemetry
Thank you for your reply.

I am not sure what you are trying to do with your clarification here, but I feel even worse about Terminal and your employer.

> ~1-5% of those entries make it into a data pipeline that I believe we stopped looking years ago.

Can you elaborate? What does that mean. 1 - 5 % of what exactly? Of all records collected? Of the records on my machine? I thought those were localized traces, do they end up on MS servers or not? What criteria are used to reduce the data? You believe that "we stopped looking years ago". What does that even mean? You not sure what confidence interval "believe" accounts for, but the error term is a bit high for my taste. And as for "we stopped looking years ago": I feel offended. You must think that I am very naive (that extends to all readers here, but I will only speak for myself here).

The code is clearly labeled telemetry, yet you claim that this is soley about local traces. If I am to believe that to be true, that makes me distrust your software even more, because then it must be of very poor quality. How do you fix bugs quickly, given that you engineers can't differentiate "local traces" from "telemetry". The latter literally means "to measure from afar". The fact that you opened a GH issue about this makes me want to believe you; the fact that it's locked doesn't; but hey, that's your dev process and community work -- I won't judge that.

As for your next argument: "It's the OS'es fault". I don't care whether the OS vacuums all my data and sends it to your employer, or whether you personally break into my house to exfiltrate my harddrive: I don't want you to obtain my data in any way. This makes it even worse -- the application you're responsible for appears to passively creates some sort of profilable data, which the OS exfiltrates. This does not remove you from the responsibility.

Also: Please consider the bigger issue here. I really want Terminal to be a great piece of software. I would consider myself a Windows fan, if it wasn't for the ongoing disrespect of my privacy; Windows is unmatched in terms of stability and consistency and a proper terminal has been missing.

Your employer claims to gather data as to improve the software I use in my interest; despite the fact that I (and many others) keep telling them that they are REALLY interested in retaining the right to privacy, individualism and secrets.

This is about trust. You keep breaking it. I don't trust you, and I don't trust your employer. When I tell you and your peers so, your answers are evasive (GH issues is not the right place), hazy (oh THAT is done in another component), bureaucratic (look at all these legal statements), irresponsible (it's the OS), or otherwise elusive (that thing clearly labeled Telemetry doesn't do telemetry, because @architechture). You don't understand the problem and you don't really care. I believe you stopped looking at that "pipeline" years ago.

cessor··on Windows package manager does not permit opting out of telemetry
I find it outrageous; "Telemetry" is built into most new Microsoft software. For example, they recently released a replacement for powershell and CMD, called "Terminal 1.0", which also comes with some aggressive telemetry built in:

https://github.com/microsoft/terminal/blob/master/src/host/t...

This also applies to newer releases of powershell, aka PS Core. I haven't tried either, but I guarantee you telemetry in both applications is not opt-in but opt out using some obscure method, if that is even possible.

In any case, the claim that telemetry is necessary to improve anything related to customer experience is ridiculous. Not only is a general data collection unnecessary; it would be more efficient to run some experiments, and be it some opt in A/B tests. Surveillance like the above is encroaching and can easily be abused. The data collected are usually fine-grained enough to allow for some nice fingerprinting of individual users. The potential for abuse is high.

cessor··on Don't set the language of your website based on user location
Three things: - YES, you are 100% right - Keepass has a Ctrl+V mode, which pretends to type into username / password fields char by char. maybe this feature can give you peace of mind - Still, you are right, the website shouldn't make assumptions on how you handle passwords
cessor··on Suggest HN: No April Fools this year
I 100% agree with not doing April fools. Humor is important; jokes work with twisted semantics and surprise. April Fool's websites have neither and just render the web useless for a day.
cessor··on Alan Kay: Smalltalk is not about objects, it’s about messaging (1998)
Also Java:

bank.move(new Amount(100), new FromAccount(checkingAccount), new ToAccount(savingsAccount));

If you are really trying, you will be able to convey enough information so that your fellow programmer. will understand what you are trying to accomplish. Unfortunately, in practice, even Java Experts will convey to you that this style is wrong, classes and objects are " too expensive", primitive values are fine, and that this is too verbose.*

I learned about this style from Yegor Bugayenko's Book "Elegant Objects", go check it out. https://www.elegantobjects.org/

*) Yes, Java is verbose; not trying to defend that. I am very happy about keyword arguments in Python, for example. But, as soon as you have classes, ctors, objects, you can use them to add rich semantics into your code. Works with functional languages and other, better typesystems, too.

cessor··on Microsoft Displaying Ads in Powershell
I didn't know where to bring this up. At this point it just feels like remote code execution. I filed an issue on PowerShell's github page. Please support me, maybe I can make my voice heard. I am tired of stuff like this. Notifications here and there, ads here and there.

https://github.com/PowerShell/PowerShell/issues/10779

I have been anoyed with my Android apps for a while now since every other update seems to change the UI randomly, I thought my shell was safe. This is not a desired piece of information, it is simply remote code execution. Somebody runs software on my computer and I don't get to decide what it is. I had Microsoft Teams installed, and now my shell is showing ads. If it wasn't for steam and photoshop, I wouldn't even run windows. So tired of your s*, Microsoft.

cessor··on Ask HN: What are some of your recent failures?
Most recent: Failed to get out of bed this morning at the time I comited to the night before. I wanted to get up at 8, be at work around 9, got in at 10/11. Fairly recent: I have been doing it like this for three weeks now

My larger failure: I was hired as a contractor/consultant by a major media company earlier this year to help the team develop some cloud based software. I was hired to improve their testing karate. When I started, I was constantly being blocked; all my ideas were rejected and the team kept reverting to they way they had always done it. After 1.5 months the teamleader threw me out. Another team leader was happy take me, there, things were doing great, but I struggled to refactor the mess of TypeScript-AWS-Lambda-Cloud-Crap in a meaningful way.

Not all of it was my fault; the situation there was horrible. But I believe someone more experienced than me, or just someone who doesn't get as emotional as quickly as I do could have handled the situation way better. I feel like a failure.

I am frustrated by the situation, because while it was going on, I felt that I was doing everything right. Not sure what my lesson is.

cessor··on How to Write Unmaintainable Code (2017)
The idea of a type / class / object here is equivalent in that they provide locality of interpretation. There is one place that may contain the code that manipulates these values; in other words, there is one place that contains your understanding - your interpretation - of the integer.

You (i.e., all commenters in this thread somehow disputing the AccountId object version of the story) are completely right, it is difficult to decide up front what you need. Of course, depending on your domain, it may be perfeclty valid to have -5 years or 1800, but I am not asking you to never implement years like this, I am merely suggesting that it is useful to have one place where such decisions, invariants, roles - your understanding of a year, perhaps specific to your domain - are located.

How your understanding is structuring is a different concern, because of course, a class with 10000 LOC is horrible to work with. But you can always use means of abstraction, and compose independent modules. An int does everything, maybe in one context a year shoudln't be 1800, maybe formatted as 4 digits. A year class / type / object is the place to store these decisions. As I outlined, such decisions are both technical (how many bits?) but may also be domain specific (year must be > 1800). Maybe you have an int internally, but abstract it with a non-zero int.

It boils down to interpretation. An int allows for many operations, but they may be invalid (in the sense of "implausible", or "undefined"). For example, an account ID of 1 can be multiplied by 2 and then by 2 again, and so on. Integers form a relation this way, but not all extensions of this relation might be "meaningful.

Integers as ids are a great example for this. Technically, they are great, because they are simple numbers, can be typed on a keyboard, and be readily interpreted, but not like integers.

6 people two times as many than 3 people. In Germany, grades are marked 1 - 6, (1 = very good, 6 = very poor). But the relationship is merely ordinal. A grade of 4 is not "twice as bad" as a 2, although the numbers are relatable that way. An Account ID of 6 is not twice as "good" as an ID of 3. For ids, you want them to identify, in that they are exclusive and exhaustive - but integer IDs are not supposed to be ordinal (in that their sizes are comparable in relation to each other, 6 > 5 is an invalid statement). Of course, you can retain this interpretation, e.g. an auto increment id would indicate that id 6451 was created WAY later than ID 6, but this is difficult to interpret; because it doesn't really tell you how much later, and also deletion of integers in between a range may be reissued (id 1, 2, 3, 4, delete 3, 3 is a missing rank, 3 could be reissued). So ids aren't ints, because they are exhaustive, but they aren't ordinal, or at least interpreting them ordinally is dangerous, and some operations aren't allowed even if you interpret them to be ordnial; for example, it would not make sense to calculate an arithmetic mean from integer ids, although mathematically this operation is allowed. In statistics, this concern is discussed as the Skalenniveau (German, meaning Level Of Scale), in English it's called level of measurement [1].

In sum, it does not matter what your usecase is, an int is an int, but depending on your use case, it might be worthwhile not to pass an uninterpreted integer around, but actually wrap it in some kind of object, where you localize all your decisions how to interpret the integer.

None of should be derogated as some form modern hipster javascript, where none of us highlevel kids don't know how to bit-bang a set difference from some account ids; but rather, these ideas are really old. Even in C, data abstraction is useful, in that you don't fiddle with integers but define a set of methods, possibly in a module that interact with a hidden internal representation. Deciding on where to cut these modules appears to be a difficult task, but we all have known this for a while now [2].

As I said, nothing wrong with bitbanging, but encapsulating interpretation in types, classes, objects, modules or functions is a useful strategy to reduce the complexity, and you lose all of it when you just pass integers around and cross your fingers and hope the next developer won't calculate a mean from your integer ids.

And finally: The performance argument. Tell me how many requests/ops per second you need and let's find out why your program can't do them. Make it work, make it fast, not the other way around.

I have had too many arguments where people talked about "performance" without stating numbers. I had a colleague who argued that joins were bad, because they were slow (which conceptually, they are), but then your database is a highly optimized processor to do exactly these operations. Their fear of table-joining yielded a database with few tables, each of which had very long columns, each of which contained values separated by two semicolons, which they would then manipulate using string manipulations. Also the table grew, because the lack of normalization caused a lot of redundancy. I have seen many sins in the name of performance, and I will kindly ask about some numbers. Performance without numbers is not a good argument against data abstraction.

Also it can usually be handeled. If your high level Python program becomes too slow for some reason, feel free to implement the slow parts in a really fast language and add a clever algorithm in assembler; see for example np and scipy.

These approaches aren't mutually exclusive. "Please don't do it" and "considered harmful" doesn't get us anywhere.

Anyway, coming back to the topic of the thread: How does code become unmaintainable? By following rules of thumb without thinking on their contextual requirements, and most often by passing around integers in the name of performance, while ignoring locality of decision, locality of code, and ease of comprehension. An int is memory, and account id is an intentional interpretation of this memory (an int also being an interpretation of memory already, I get it, this is about abstraction - and finally, true comprehension comes from world-reference. The int doesn't care whether it is 5. You do, see above.)

RAM and CPU power are less expensive than two developers wasting their time trying to understand some low-level code and identifying which functions expect an int64 and which need a size_t, and whether they are equivalent, and so on, while they could just be passing around some thing with a stable interface, and a localized world-reference (you know, a name).

I wouldn't argue that all of this object/type stuff it is THE way to go, but these treatments were all invented specifically to solve the issues of raw-integers. And certainly I am quite ok with the fact that not everything uses Java; however the ideas we're talking about here are not specific to Java, and Java in particular often provides a very poor version of the story.

I would, however argue, that it is important to be congurent to the unit of expression of your programming language. Treating C as if it were object-oriented will give you a bad time, and not using objects in C# and Java will also give you a bad time. If your language natively provides an optimized iterator pattern, as does Python, coding in the C-for-loop-index idiom will give you a bad time. Most unmaintainable Java comes from not understanding Java, because you mistake it for C without & and *, but with Objects.

Unmaintainable code is about people. Code doesn't maintain itself.

</rant rel="sorry">

[1] https://en.wikipedia.org/wiki/Level_of_measurement

[2] https://dl.acm.org/citation.cfm?id=361623

cessor··on How to Write Unmaintainable Code (2017)
Many people are pointing out that short identifier names are ok, and that i is perfectly fine as an identifier name. It likely is, and I believe the rule to be true that short identifier names are ok for short scope / context. However, there are several issues:

i for an index is ok, but this is a red herring: You only ever need an i for imperative iteration and in a sufficiently high level language you are better of with selection and projection, (iteration for that matter), where you just foreach over each element and don't actually need to ask for things by index. Sure, y'all be hacking C, nothing wrong with that, it depends on what you str doing, but for comprehension, the mere existence of i is a red flag, because most of the time you want something to happen to a collection if things and foreach is perfect for that (or map, fold, filter, pick your poison).

Still, a better example than `i` for short identifier names would be x,y,z, or r,g,b These are so common and conventional that I would expect them to have semantics of their own, still they could be chunked to types such as Coordniate, Location, or Point, or Paint, or Color, respectively. But comming up for better names than x,y,z is really difficult, will bloat your code and make it hard to understand what is going on.

I am pointing this all out, because many of you seem to favor such very short identifier names - and I am with you: sometimes they make sense, see above - but empirical evidence suggests that very short identifier names, and single-letter identifier names in particular significantly worsen comprehension of code. The same is true for abbreviations (depending on how strongly you abbreviate).

[1] https://ieeexplore.ieee.org/document/7884623/ (disclosure: author)

[2] https://doi.org/10.1007/s11334-007-0031-2

[3] http://compscinet.dcs.kcl.ac.uk/JP/jp040302.abs.html

[4] https://dl.acm.org/citation.cfm?doid=382080.382628

[5] https://link.springer.com/article/10.1007%2Fs10664-018-9621-...

Preprint for [1] here: https://brains-on-code.github.io/shorter-identifier-names.pd...

[5] is the extended Version of [1] including discussion of how attention is shifted during the experiment. It turns out that, when code uses words as identifier names people don't need to read the comments as much.

cessor··on How to Write Unmaintainable Code (2017)
I agree with @scarface74 and would go even further in that I would probably create a custom type for List<AccountId> to convey the purpose of what that thing is now.

And as for the "type shyness":

> Creating a new datatype for something as simple as an int or String defeats that and makes it more cumbersome to work with.

It is never "just an int". Soon you will ask questions about the int, and in a sufficiently large application you will forget the answers to the quesions easily, and scatter the same question (i.e., the same boolean logic) all over the place. Consider an application where you need to filter something by year. A year, you know? As in 1974, 2018, etc. An int is bad, because an int could be -5, which does not make sense. Ok, a uint then? Still bad, because then there is a year 0 and - if your application deals with birthdays of real people, 1800 would be an invalid birthday. The semantics (or pragmatics, linguistically speaking) emerge from how you interpret the integer, and this interpretation can happily live in that one file with that one class that encapsulates "just" that integer.

The AccountId probably shouldn't be < 0, and a specific type could be the one place where you make sure that this is always the case.

What if you start with a 32bit integer and suddenly you realize that your weird Internet-Of-Things-Sensor reading database has grown and the 32bit integer is getting too small? You could just use 64bits. With "just an int", you now get to change every single function that expects an int for the purpose of a SensorReadingId (or an account id or whatever) and change it to size_t, uint, int64 or whatever. OR, you just tell the object that its internal representation uses 64bits now, because the AccountId class is the one single place that deals with account ids. The type provides a consistent interface that allows you to infer the semantics of its use. An int doesn't do that.

This idea predates java by some ~20 years [1]. An int is not an account id. An int is not a year. An email is not a string. The result of working like that is considered a code smell [2].

Still, coming back to the example I made: It was primarily about commenting. I was taught to always comment, and StyleCop enforced comments on each and every field of a class, leading to noisy, superfluous comments.

    /// Gets or Sets the Name
    string Name { get; set; }
does not add anything.

As for returning an AccountID: I'd like to point out that the Account is a strong and independent object, who can make his own decisions and does not need to return anything. Returning its id like that is actually breaking encapsulation. Still if you do it, it probably shouldn't be an integer.

Why are people scared of creating types and objects?

[1] https://link.springer.com/chapter/10.1007%2F978-1-4612-6315-...

[2] https://sourcemaking.com/refactoring/smells/primitive-obsess...

cessor··on How to Write Unmaintainable Code (2017)
I found this technique to work quite well, but this idea does not mean imply that one should simply "quit writing comments", but rather that comments can most often be replaced with actual structures that improve the code (e.g., extracting long boolean expressions into a function with the same name as the actual comment), but that also depends on the language and aptitude of the developer.

Would you really argue in favor of something like this?

``` class Account { ... /// returns the accountId public int d_nr() { ... } } ```

``` class Account { ... /// returns the accountId public int getAccountId () { ... } } ```

The first comment is obsolete when using a proper method name, the second does that and so the comment is redundant.

May I ask: What did you experience in the wild?

cessor··on How to Write Unmaintainable Code (2017)
Could you elaborate what criteria you apply to decide whether something is "as humanly readable as possible"? I am asking out of genuine interest, I am researching readability and I am interested in how you make decisions and what criteria you apply. What means "readable" to you?
cessor··on On incomplete HTTP reads and the requests library in Python
I fully agree with you.

Altough I really like requests, this is a violation of one of the PEP 20 heuristics:

Errors should never pass silently. Unless explicitly silenced.

https://www.python.org/dev/peps/pep-0020/

An exception would be an elegant way to handle the problem and would be able to retain the incomplete data to be handeled. It's exactly what they are for. The exception could be the default to prevent surprises, possible deactivated with a flag.

cessor··on Ask HN: What stack should I use to build my basic web app as of 3/29/18
That's the third of Thunderfiretober of 2018, what's your problem, isn't that clear? ;)

Playing devil's advocate here. This kind of date formatting is really confusing to me (German) and I almost overread that the question asked for the current en vogue tech...

cessor··on JS Paint – A web-based MS Paint remake
The site works nicely in my browser (Chrome).

I feel like this mockumentary is not getting enough credit:

https://www.youtube.com/watch?v=K9L03GycSZw

- "We worked for eight months in a facility in California to figure out what were the best twelve colors to include in Paint"

- Can we make this line thinner? - No. - Ok.

I have not used Paint for any real work in the past, other than saving screenshots. Ever since MS started shipping the snipping tool, I hardly use this function.

cessor··on Excel team considering Python as scripting language: asking for feedback
I use PANDAS in Jupyter Notebooks a lot. Sometimes, exploring large data frames can get tedious and I find myself loading up excel to explore and browse around, usually when deciding how to normalize or clean things up. Using Excel as a PANDAS Gui this way would be really great, but also using Python to script excel would be useful. And I guess I would love to call bokeh / seaborn after making an excel cell selection.

I am looking forward to what a Python & Excel marriage will look like.

cessor··on Ask HN: CS and programming books of 2017
My highlight was Yegor Bugayenko's "Elegant Objects". Volume 2 was released this year (however I found the first Volume (2016) much better).

Yegor describes what went wrong with object-oriented programming. Whether you are stuck with Java or broaden your horizon, I can really recommend this book series, as it shows nicely how to deal with object-oriented code in the right way.

What was eyeopening for me was that code, written after some of the rules he proposes, becomes indistinguishable from functional programs. One example of a tree of objects resembles a LISP program. This all made me realize how flawed some of the arguments are that to me seem to divide the functional/types and OO camps.

https://www.amazon.com/Elegant-Objects-1-Yegor-Bugayenko/dp/...

https://www.amazon.com/Elegant-Objects-2-Yegor-Bugayenko/dp/...

The books are short and relatively expensive, but Yegor claims to refund 20 euros for everyone who is willing to write a blogpost.

cessor··on How Stripe Designs Websites
Is... is this an ad for stripe?
cessor··on Show HN: Learn what DDD, CQRS, and event-sourcing are all about
Could you elaborate?
cessor··on Efficient music players remain elusive
I came here simply to mention foobar2000, and I am happy that many people before me did. Some mentioned they missed it on Linux.

I am a Windows user myself, but I feel "ncmpcpp" is a good alternative on linux (apparently that's an Ncurses Music Player written in CPP). Simple, console list interface with good features.

cessor··on Ask HN: What language-agnostic programming books should I read?
Good advice! I have an older version, in which the implementations are explained in Pascal. I understand that newer issues cover java. I'd believe the book goes well with his coursera course:

https://www.coursera.org/learn/algorithms-part1

cessor··on Ask HN: What language-agnostic programming books should I read?
Here are my recommendations. Each is a placeholder for a complete discussion :)

Psychology of Programming

=========================

1. "Psychology of Computer Programming" - Gerald M. Weinberg

2. "Software Design – Cognitive Aspect" by Francoise Detienne

3. "Thinking Fast and Slow" by Kahneman and Tversky

4. "Drive: The Surprising Truth About What Motivates U" by Daniel Pink

Book 1 is a really nice read and touches a lot of the social and workplace aspects of computer programming. Book 2 is more focused on modern research of program comprehension in relation to cognition. It's a little older, and often just scratches the surface, but they both nicely show that a lot of social and psychological factors are relevant for programming, independent of the programming languages developers use. 3. and 4. add some more background infos to it if you want to dive deeper.

Career Development

==================

- "Hackers and Painters" - Paul Graham

- "The Passionate Programmer" - Chad Fowler

In addition to the Pragmatic Programmer which has been mentioned in other comments, these books really helped me understand where I wanted to be as a programmer.

Technology

==========

With a stronger focus on technology I recommend:

- "Language Implementation Patterns" - Terence Parr

- "A Retargetable C Compiler: Design and Implementation" - Hanson, Fraser

I found them more helpful than the Red Dragon Book. The latter is good, but as a beginner I felt a little lost and Terence Parr's book was much more helpful.

Practice & Karate

=================

- "Elegant Objects" by Yegor Bugayenko

- "Working Effectively With Legacy Code" - Michael Feathers

- "Growing OO Software, Guided by tests" - Pryce, Freeman

- "Test Driven Development" by Kent Beck

And, this last one I can't recommend enough:

"XUnit Test Patterns" by Gerard Meszaros

Kent Beck's TDD is good book to start with. Even if you feel like you have got testing figured out, you should try TDD. It has more to do with discipline and getting things done, rather than writing code fast or smart or efficiently. Someone I follow on twitter once called it "thinking at sustainable pace", which is really what TDD is about. A lot of people are simply offended by the idea to "test first". To me, "test first" is roughly equivalent to "think before you code". Maybe this is what others find offensive.

As for an advanced view on testing, Gerard Meszaros's book is really good. It is a catalogue of testing patterns that helps to structure testing code in a nice way.

Depending on OP's skill I would recommend the following: Be very carefull with the following books:

- Design Patterns - Gang of Four

- Patterns of Enterprise Application Architecture

- {Doing Anything with} Domain Driven Design

These books are really valuable, but somewhat problematic. Sometimes they will give you a hammer and make everything look like a nail. Sometimes they make it easy to focus on the wrong things. They come over as precise and clear, but really aren't, which will cause discussions and poor choices. On the surface, they sound nice, simple and friendly, but on a deeper level, they are really difficult to understand.

If you want to read them, I encourage you to do so with your colleague and discuss them critically. Maybe you can have a wednesday afternoon bookclub meeting at your company. We once did that for "Working Effectively with Legacy Code".

I collected some more suggestions on a trello board a while ago, which should be accessible here:

https://trello.com/b/lw96ei6d/books

If you wish to contribute, just let me know. Then initial collection started when we got together after an open space.

BTW: Thank you all for your suggestions! I will add some of your recommendations to the trello board.

cessor··on How to Improve a Legacy Codebase
I'd add a prerequisite to the top of this list:

- Get a local build running first.

Often, a complete local build is not possible. There are tons of dependencies, such as databases, websites, services, etc. and every developer has a part of it on their machine. Releases are hard to do.

I once worked for a telco company in the UK where the deployment of the system looked like this: (Context: Java Portal Development) One dev would open a zip file and pack all the .class files he had generated into it, and email it to his colleague, who would then do the same. The last person in the chain would rename the file to .jar and then upload it to the server. Obviously, this process was error prone and deployments happened rarely.

I would argue that getting everything to build on a central system (some sort of CI) is usefull as well, but before changing, testing, db freezing, or anything else is possible, you should try to have everything you need on each developer's machine.

This might be obvious to some, but I have seen this ignored every once in a while. When you can't even build the system locally, freezing anything, testing anything, or changing anything will be a tedious and error prone process...

cessor··on Britecharts: D3.js based charting library of components
I felt the same way. The examples are accessible, but a better overview would be helpful.
cessor··on Writing good code: how to reduce the cognitive load of your code
klibertp,

> another thought on the study: does it control for presence or absence of widely known conventions?

I am very happy to encounter other critical thinkers - your question is a really good one :) You are right, the study is not capable of explaining this effect (that is, how commonplace / conventional some abbreviations are), but it was considered in the design. I am sure that this plays an effect but I wouldn't dare to give a definitive answer based on the data from my study.

For example, config or cfg are arguably so common that there they don't hurt comprehension. Similar for single letter variables. Point.x and point.y are easily identifyable as coordinates. Or the variable name i in a for loop may not be problematic, as it becomes almost meta-syntactic (much like foo and bar). However, i,j,k,l index names may really hurt comprehension, when you have a complicated looping strucutre with many lines in between, as they are likely to strain your working memory. As for the point.x example: I would explain this as a priming effect. The name of x is fine, because point already preactivates the right direction. X in isolation might be worse, and if you encounter new MessageBrokerInstance().X() you might as well read your code in base64... Thus, based on my experiment, I can talk about variables in isolation, but usually, code is mixed and here, other effects might be relevant.

In the longer versions of my experiment, I considered the effect of common abbreviations as well. Psychology lists several word frequency effects. Common words can be immediately accessed *(from the so called mental lexicon, a mind-dictionary if you will), but uncommon words have to be synthesized on the fly though their phonetics (see, for example the dual route cascade model, coltheart 2001, http://www.cogsci.mq.edu.au/~ssaunder/files/DRC-PsychReview2...). Thus, high-frequency words (=often occuring, common words or strings) are quickly read and their meaning is understood, whereas uncommon words or strings do not have a representation in the mental lexicon and you have to synthesize their meaning first, thus slowing down comprehension.

My argument is simple: It is always possible to understand code, no matter how mangeled or obfuscated it is (after all, reverse engineers are doing amazingly hard work). The question is how easyly the code can be comprehended. Abbreviations that are common to some (e.g. experts), may not be common to others (e.g. novices in their first job). Of course, the newbies will get there eventually, but abbreviations have a higher learning curve, thus new people will be unproductive for a longer time.

Think about yourself, you surely know this effect:

1. Write code. 2. Problem solved 3. don't touch it for 4 months 4. Changes needed, need to fix bug, add feature 5. How does this work? 6. Wtf, what was I thinking?

For the sake of all newbies, your company, or even your own, I encourage the use of identifiers that can be read, because you can READ and know LANGUAGE, and not because of arbitrary conventions. There are many conventions (e.g. x:xs, for i=0;i<10;i++, point.x) that can surely be considered domain language and don't impede comprehension, but still might hinder comprehension for novices, or yourself in 4 months.

> how relevant/applicable you think the studies you linked to are in the general case?

This is really hard to say. Many processes take place when programming, and many programmers have theories about why it is hard and how to make it easier (as the entry article citing cognitive load, which is a good methaphor, imho). So far, I know of many such scientists who are trying to isolate the different effects. For example, I am focused on identifier names, as I find them to be impactful. Their meaning can't be analyzed automatically (even with sound nlp techniques which are relatively limited), and the programmer is totally free to name their variable names what ever the hell they want. I am sure that in comprehension of programs, identifier names play a big role, but when I encounter "clever code", with weird recursions, counterintuitive measures, or plain magic (https://en.wikipedia.org/wiki/Fast_inverse_square_root) the value of identifiers are limited, or, in other words, there are other things going on that impact my comprehension BESIDES identifiers. How they interact, I cannot say for sure, but if complex code has no clear identifiers, it becomes complicated.

I believe that each of the effects in isolation is relevant, but I am not sure which one is the most dominant, or, for that matter, whether there is ONE thing that will solve all problems.

cessor··on Writing good code: how to reduce the cognitive load of your code
As my other comments outline, there is some science, although you are right in that empirical work on software engineering is a very small niche. Most people just report studies like:

"Hey, look what I cooked up in my basement using haskell".

- which to me, is engineering, not science.

cessor··on Writing good code: how to reduce the cognitive load of your code
> That's because no one even knows how to start doing "science" in this direction

I am sorry to disagree, but this is just not true.

http://www.ptidej.net/courses/inf6306/fall10/slides/course8/...

http://www.cs.kent.edu/~jmaletic/papers/EMSE12.pdf

https://link.springer.com/journal/10664

https://scholar.google.com/citations?view_op=view_citation&h...

I have to say this:

https://brains-on-code.github.io/shorter-identifier-names.pd...

My supervisor has to say this:

http://pi.informatik.uni-siegen.de/stt/34_2/01_Fachgruppenbe...

These are just the ones from the top of my head that I can google quickly, if you want I would be happy to share my zotero database or a large bibtex file.

> When you read the code there are so many different things influencing your understanding that it's hard to impossible to even list them all.

You are completely right: Psychological research on programming shows that it is a very complex cognitive task, best done by experts, and poorly understood.

You describe knowledge and experience, and they in fact matter a lot. The above studies, for example, show (often just as a sideeffect), that experts are impacted less severely by badly written code (however that was operationalized).

> Literate Programming should be the default by now

I agree.

← PreviousPage 2 of 6Next →