9 ms·
I think i’ve got a slightly different take - i’m not saying my take is any better though. If we’re talking engineering principles, not team dynamics, then it’s
by CraigJPerry 5y ago
I think i’ve got a slightly different take - i’m not saying my take is any better though.
If we’re talking engineering principles, not team dynamics, then it’s:
1. Use immutability by default, even in languages that make that harder than it should be
2. Understand how liberating idempotency is
3. Divide and conquer, use abstraction to make hard problems manageable
4. Delete code, delete tests, re-write stuff, re-write it again. Painful? Keep doing this till you get to the other side and feel liberation and empowerment, took me years to get past wincing at the idea of re-writing that thing AGAIN
5. Pay attention to your build tooling - to do any given task, it should always take exactly 1 command. How do i run the tests? Run the test command. How do i deploy to non-prod? Run the deploy command. Etc
If we’re talking softer stuff:
1. Don’t block collaboration - e.g. if there are 5 people don’t work on 5 tasks concurrently. Work on 1, maybe 2 in some cases
2. Accomodate 2 types of work: work that needs collaboration & synchronisation (brain storming, planning, why are we even doing this, that kinda thing) work that needs focus time - sometimes that’s focus as an individual, sometimes that’s a mob focussed on one task and saying no to every other distraction in the world no matter how “urgent”
3. Change what you’re doing throughout the day, don’t try to code all day, you’ll get in a rut, you won’t write your best code after a while. You can optimise this step, e.g. if the team is low energy after lunchtime, use that to your advantage and schedule the easy boring work then, don’t be afraid to use humour or burn low energy time just getting to know each other better
4. Make sure people are being heard in the team. Hardest point to get right.
- AdamCraven 5y agoI really like that you've thought about these - and feel free to submit them not only will you get a founding badge but if you're the first person to create it you'll be known as the source of them in the future. It's not really about better or worse, what I've found is different people have different backgrounds and what principles they find useful is based on several things, which may be immuntable - such as strongly held values. You're never going to make me not care about aesthetics for example, as that is intrinsic to me and that will affect the principles I like and ultimately the people that I work best with. An analogy I like to think about is that people with very different principles are like two people holding a rope and pulling away from each other - you aren't going to get anywhere fast. Whereas people with similish principles, will generally go in the right direction. Sure, they'll get tangled up from time to time and you won't always want to get in exactly the same way. But there's a collaborative nature to it and you'll both improve.
- Jenk 5y ago> feel free to submit them not only will you get a founding badge but if you're the first person to create it you'll be known as the source of them in the future. That sounds wrong. As in "I could upload quotes from Gang Of Four books and claim I am the source" wrong.
- AdamCraven 5y agoA lot of thought has gone into the licensing. Hopefully I've covered all bases. You can't be an author if you aren't the author of a principle or the principle is too generic. If the principle is already open source (e.g. on wikipedia, has a creative commons license) you can submit it but not claim you are the author for it and submit it under the same licensing terms (CC-BY-SA) as long as it doesn't break the license. Codifying the principle for the first time takes effort and people can iterate on it to make it better over time. Many people may have had similar thoughts before, but if it's not a general principle already being used the first to turn it into a principle - to put a stake in the ground - benefits everyone and can help improve everyone's capability. I believe the author should be rewarded for that effort, as long as it is their own unique work.
- lupire 5y agoThis sea a lot more work for no benefit, compared to just writing a (hypertext) book and citing sources.
- AdamCraven 5y agoThe eventual benefit is having access to many community sourced principles as a resource, which are getting better over time as people contribute. Then being able to create your own lists for unique situations. Say "Lupire's CTO list" or "Lupire's management principles" and to share that with your team or as a reminder to yourself. Of course you should always be able to export it and put it in a format that's useful to you. And that's been really important to the design. From using markdown format to embedding license information and meta data with the principle, it should help a lot with portability.
- mrits 5y agoDon't expect a better result after a rewrite. Be prepared to accept that.
- chii 5y ago> Don't expect a better result after a rewrite but what's the point then? why spend effort for it, if it isn't expected to be better?
- TeMPOraL 5y ago> but what's the point then? Learning. The result may not be meaningfully better, but you gain fuller understanding of the problem domain. The third rewrite might have a chance of being an improvement ;).
- lowercased 5y agoYou may just learned that there's no more meaningful improvement to be made. That should probably be documented somewhere after that discovery is made. Somewhat relatedly, I've refactored processes down from 25 hours to 20 minutes. It got to 20 minutes, and other people started nitpicking that it could 'be faster' (the same people who'd let it get to 25 hours, then threw up their hands and said "it can't be fixed"). They spent loads of time getting it from 20 minutes down to... 17-18 minutes (spending 2+ weeks in the process). I'd indicated "there's really no more 'there' there - this is about as fast as it's going to get, without faster hardware". They had to find out for themselves there wasn't much more juice left in the tank. Maybe it's not related, but I felt like sharing it anyway... :)
- bobthepanda 5y agoMeaningful improvement is in the eye of the beholder. There's the old tale of how Google found out 500ms in latency was a 1% drop in traffic. http://glinden.blogspot.com/2006/11/marissa-mayer-at-web-20.html http://glinden.blogspot.com/2006/11/marissa-mayer-at-web-20.... 20 to 17 minutes is a 15% time savings still.
- macintux 5y ago> Use immutability by default, even in languages that make that harder than it should be That and referential transparency are huge wins. It is a shame languages like Python make it such a challenge.
- wlpu 5y agoIt's easy to do immutability in python, just use NamedTuple for classes and tuple instead of list
- macintux 5y agoI’ll research those, thanks. Any suggestions for OSS projects that do so today?
- gravypod 5y agoThis is a good talk that demos NamedTuple: https://www.youtube.com/watch?v=wf-BqAjZb8M https://www.youtube.com/watch?v=wf-BqAjZb8M
- japanuspus 5y ago...or `dataclass(frozen=True)` if you need the ergonomics. For non-primitive members, `frozenset` is in the standard library, but frozen dictionaries are unfortunately lacking.
- joshuamorton 5y agoPlease don't do this, there are far better approaches. Use dataclasses/attrs that are frozen for immutable record types. (Specifically avoid namedtuples unless you're hoisting a tuple to a real record. Record types also being a weird union with a tuple is...oft confusing) For immutable basic data types, adopt type annotations and prefer to use sequence/iterable and mapping to direct didn't/list types. These provide statically verifiable immutability and also allow begin to encourage useful async-friendly patterns.
- rurp 5y agoI second this. My current job is the first place I've worked where the convention is to use NamedTuples for most things I've seen dicts used for on past projects and I quite like the pattern. It both makes the code more readable and avoids a number of subtle bugs that can crop up.
- hammock 5y ago> 2. Understand how liberating idempotency is Can you give some examples?
- e40 5y agoAnd is another way to say this "side-effect free"?
- rcfox 5y agoThe Linux shell command 'touch foo' is idempotent, but not side-effect free. Reading a variable shared between threads without a lock is side-effect free but not idempotent.
- majkinetor 5y agoEverything is great there, and in particular number 2 is awesome and 5 is FTW ! Also, don't let people guess what are those commands - create a menu that is run as soon as you clone the repo and shows all commands. I now use Invoke-Build [1] system for that and on all projects you type ib ? to get that list and later ib <task> to execute it (or any combination of it, i.e. ib DropDatabase, Run, Test). Basic tasks are named the same on all projects no matter the underlying technology. Later you use the same command on CI server - its just another developer that runs ib Build, Test, Publish. Any more programming in CI yaml files then 1 to 3 lines per job is so wrong. [1] https://github.com/nightroman/Invoke-Build https://github.com/nightroman/Invoke-Build
- RussianCow 5y agoI agree with everything except for this: > 4. Delete code, delete tests, re-write stuff, re-write it again. Painful? Keep doing this till you get to the other side and feel liberation and empowerment, took me years to get past wincing at the idea of re-writing that thing AGAIN With experience I've realized that rewrites are almost never a good idea[0]. They are time consuming and inevitably introduce new bugs (or reintroduce old ones), and the benefit is almost always marginal. If your architecture allows it, it's better to sandbox working legacy code and leave it as-is than constantly rewrite it. My own policy is: if you're making significant changes to a unit of code anyway, clean it up or rewrite it; otherwise, make the smallest change necessary and leave it alone. If it ain't broke, don't fix it. (Obligatory Joel Spolsky article on the topic that everyone has probably already read: https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/ https://www.joelonsoftware.com/2000/04/06/things-you-should-...) [0]: ...with a possible exception if you're at a very large tech company with a lot of resources, where the testing/QA processes are a lot more thorough and it's possible to keep up with constant changes like this. But even then, seeing the amount of bugs introduced with each update to Facebook or Gsuite or any other large piece of tech, I'm skeptical.
- bob1029 5y ago> With experience I've realized that rewrites are almost never a good idea [...] If your architecture allows it, it's better to sandbox working legacy code and leave it as-is than constantly rewrite it. What if your architecture is the problem? If you got the domain model wrong and you have deeply-nested complex types used throughout, you will never break free without a clean sheet rewrite. Certainly, you can refactor bits and pieces to conform to a correct model, but it's going to be an uphill battle the whole way. 10x if you are already in production with business state tied to the legacy schema(s). Most of the horrible things I have seen at code review time have a root cause somewhere in poor domain modeling. For example: Someone put support for 2 customer addresses as facts directly in the Customer type, so now you can't deal with the new edge case of 5+ addresses per customer, or model the idea that the address might be shared between more than 1 customer (and/or some other business types). If you didn't model for 3NF/BCNF/DKNF up front, you might as well start over from the beginning in my experience. If your problem domain is not that complex, you can probably survive with something really shitty, but the moment you enter into 50+ types, 1000+ facts and 100+ relations, things are impossible to manage without strong discipline in this area.
- amw-zero 5y ago> 1. Use immutability by default, even in languages that make that harder than it should be What I've come to realize is that whenever people talk about wanting immutability, they really want value semantics. Value semantics can be achieved without immutability - the best example is Swift's structs. They can be both mutable or immutable, but they can never be shared, i.e. there can never be more than one reference to a single struct value. This means that modifying the value has no effect on other references, because there can be no other references. This makes whether or not the value is immutable irrelevant, or at least not necessary. You get the same benefits - you can reason about your code locally and not worry about your changes modifying unknown parts of the program. Local reasoning is the end goal, and value semantics is the mechanism of getting to that goal. Immutability is only one way of getting value semantics.
- valenterry 5y agoCan you explain in more detail? I agree that local reasoning is the end goal, but as soon as you change things (i.e. mutate) then it doesn't work anymore. Or in other words: if modifying a value has no effect on anything else, then why would you modify it? I don't get it - maybe a code example would help.
- chrisdirkis 5y agoAn example might be a function that takes a vector3, adds 5 to the x value, then returns the vector's length. You could model that as "make a second vector v_2 {x = v.x + 5, y = v.y, z = v.z}; return v_2.length", but if you have struct semantics, you can just do "v.x += 5; return v.length", and be confident that you're not modifying the vector that the caller has.
- valenterry 5y agoI see - but then you would still not have guaranteed local reasoning within the part of the code that modifies the vector. Is that really worth it? Also, creating the second vector should really look like "v2 = v.copy(x = x + 5); return v2.length". Or even just "return v.copy(x = x + 5).length".