|
Soricidus posted:tef please stop doing ruby it's bad for you i have come to terms with ruby a land where eval is fine but parametric classes (i.e namedtuple) are the work of the devil where each team uses a different environment manager and every month or so we move versions which requires a total rebuild. aside: i can pretty much remember the incantation brew update && brew upgrade rbenv ruby-build && rbenv build .... && rbenv rehash and then gem install bundler && bundler update. i have never worked on a project before that regularly changed interpreter versions, but then again i didn't live in a world where i hoped that this release would finally have working GC a land of nils: lists? nil. hashes? nil. instance variables? nil. there's countless other little nils that i can never recall. there is no datetime library. a land of odd things: respond_to? or is it responds_to? const_get not get_const. upcase but downcase. libraries but they're all in the same namespace and essentially include files for monkey patches to build dsls. i mean, python has namespaces, sure, but ruby, well, there's an object's constants, instance methods, class methods, and unique prototypical versions of each for any object that are not inherited. then i guess you also have local variables too. there are private methods but they just mean that you don't call them directly but implicitly. puts is a private method on Object. Every class and instance usually descends from it, and when you call puts "foo" you're calling the puts method on object which you've inherited. It's also where all your classes are stored, as constants on object. i mean, which class will be called is a fun game. globals are bad but 100 methods on your universal base class is business as usual. it's not a small wonder that A::B is one of the most misunderstood parts of ruby. no-one really knows how module lookup works, or explain *why* module A::B and module A; module B work differently, i mean, for what purpose should they be distinct? on the plus side, only false and nil are false in if statements, that's nice.
|
# ? Sep 28, 2015 01:31 |
|
|
# ? Jun 12, 2024 05:33 |
|
tef posted:it's not a small wonder that A::B is one of the most misunderstood parts of ruby. no-one really knows how module lookup works, or explain *why* module A::B and module A; module B work differently, i mean, for what purpose should they be distinct?
|
# ? Sep 28, 2015 01:35 |
|
tef posted:it's not a small wonder that A::B is one of the most misunderstood parts of ruby. no-one really knows how module lookup works, or explain *why* module A::B and module A; module B work differently, i mean, for what purpose should they be distinct? as with most things in ruby, the honest to god answer is that these fall out of the naive implementation: "module A::B" actually creates an "A::B" entry in the symbol table. because the interpreter is that stupid simple a lot of the baffling poo poo in the language comes down to how easy or hard it was to bolt a feature into the interpreter
|
# ? Sep 28, 2015 01:35 |
|
piss: :poo poo is the worst syntax design decision of any language ever
|
# ? Sep 28, 2015 03:43 |
|
tef posted:i kinda hate test driven design. i'm sure people will chime in to tell me that this isn't true test driven design, but, like agile, the name is the popular bit, and knowing the name is the average level of understanding of the practice. let's call it tdd as found in the last 2 years of ruby code bases. Agreed on the performance bit, but the assertions ought to exist in code, and the test should be exercising them to make sure they take place. More or less, the way I see it, the test would make sure nobody ever removes the assertion that should be in code at any time. The same assertion more or less should sit in specification. A codebase where the assertions sit only in code is a codebase which will see its assertions slowly taken out through refactorings and will start failing in fun ways. Pushing this further and you may get model-checking, where you try to just entirely have a second (high-level) representation of your system or component to exercise it properly, ensure its invariants, and so on. tef posted:2. people use a hell of a lot of mocks and stubs and fakes This is true. Mocks suck. The distinction I see is that a mock provides either of the following: 1. A way to return a predictable value for a non-deterministic process. Datetime testing is an example, where a mock can be used to return time values that exercise boundary conditions (leap year, DST changes, end of years, etc.) without problem. However, mocks used that way are almost always symptomatic of too tight of a coupling -- if your code operates on data rather than through APIs, you can pass the time as an argument and assume other code does the binding through. This ends up simplifying integration tests down the line. Incidentally, the most times I'm forced to mock code is not when doing TDD, it's when writing tests for old-rear end code (as you said, 'testing untestable code') because I can't have the code testable without refactoring it, and I'm not willing to refactor without having tests to make sure I'm not breaking poo poo. The long cycle of this is hellish and it goes write lovely tests -> refactor -> rewrite non-lovely tests. Try arguing a time budget for that. 2. Prevent outrageous resource setup. I've written mocked tests for a build tool (which is an ordeal I don't recommend getting into) where I can assume files were fetched over the network and create per-case dependency trees of packages. The alternative is setting up your own package registry, generating packages ahead of time, and running tests against them. Similarly, testing for specific external APIs or handling of network failures is far simpler by just having a mock representing the failure than by setting a remote service and hoping it fails the right way. You may still need tests to ensure actual calls work properly, but those aren't the same thing. In many cases where I see mocks making sense, the tests and their setup can become as complex (or more complex) than the actual code you're testing. That way lies madness, enjoy your dockerific test runs. Mocking is a kind of compromise or shortcut there, where you trade the risk of a tower of babel test code for the hindrance of less maintainable test suites, given all your tests end up reflecting a reimplementation of an API that may change, and then you're forced to rewrite a bunch of tests. I still believe that often, that's a cheaper cost than maintaining test environments set up all the time, which is essentially an ops job. 3. A way to avoid duplicating tests. This is more frequent when you treat your code as specs, but they let you set invariants in a piece of code that you do not want to exercise 15 times through 15 tests. I'm not sure I like these much, but yeah. tef posted:3. tests slow down refactoring Incidentally, I find most tests that test implementation are those written after code, or at least the way I do it the most. It's whenever I go "okay, I feel this is good enough now, let's crystallize the gently caress out of this module to make sure it doesn't change accidentally". It's the lovely half-assed tests I end up writing when I feel my work is done and I'm too bored to return quality stuff otherwise (and why writing test first makes sense for me -- it's the best way I found to care harder about writing good tests). I also find it hard to make assumptions such as "function X gets called" when function X is not implemented yet. The other argument I'd make is that the thing that slows down refactoring the most isn't tests, it's not having tests. Because then, I gotta make sure I reverse-engineer the behavior specifications, then write tests first before refactoring to make sure I don't actually break anything. If you write good tests, I don't really give a fart whether they've been written before or after the face. If you omit them, though, then I hate you down the line when it comes to maintenance, because the work has just been shoveled forward for whoever touches that code next. tef posted:4. testing isn't free Agreed.
|
# ? Sep 28, 2015 04:04 |
|
tef posted:who will tell you about the magic of type inference until you ask them about monomorphism restrictions and row polymorphism and they look sad MALE SHOEGAZE posted:can you or anyone please explain this to me because i dont understand it ok. type inference means you almost never have to declare your types, because the compiler infers them from usage. those types may be polymorphic, i.e. instantiable in many ways. an example is the list length function, which takes a list of any type and returns the number of items in it. you can call that function with a float list, string list, int list list, etc. example in ocaml: code:
code:
code:
code:
code:
row polymorphism is great poo poo, you can basically do statically enforced "duck typing" with it, and i have no idea why tef doesn't like it JewKiller 3000 fucked around with this message at 04:13 on Sep 28, 2015 |
# ? Sep 28, 2015 04:11 |
|
tef posted:6. gently caress cucumber i'd ask if you were kidding but i mean this is ruby we're talking about
|
# ? Sep 28, 2015 04:43 |
|
Mr Dog posted:i'd ask if you were kidding but i mean this is ruby we're talking about it's true.
|
# ? Sep 28, 2015 04:47 |
|
JewKiller 3000 posted:a good post thanks, i really appreciate this post. i'm going to take some time to read it.
|
# ? Sep 28, 2015 04:54 |
|
I find the idea of cucumber hilariously bad. One more installment of 'plain English can be turned to code so that anyone can write this' that is bound to fail.
|
# ? Sep 28, 2015 05:03 |
|
MononcQc posted:Agreed on the performance bit, but the assertions ought to exist in code, and the test should be exercising them to make sure they take place. More or less, the way I see it, the test would make sure nobody ever removes the assertion that should be in code at any time. The same assertion more or less should sit in specification. I like this. Pushing this further and you may get model-checking, where you try to just entirely have a second (high-level) representation of your system or component to exercise it properly, ensure its invariants, and so on. quote:
I guess I am ok with things that stub out data *i.e. idempotent* but not things that stub out other sorts of behaviour quote:Incidentally, the most times I'm forced to mock code is not when doing TDD, it's when writing tests for old-rear end code (as you said, 'testing untestable code') because I can't have the code testable without refactoring it, and I'm not willing to refactor without having tests to make sure I'm not breaking poo poo. The thing is what when you mock behaviour, you don't get it right. these tests are a cheap facade that resembles the mess and will be based upon your understanding of the system, and not the implementation. You end up with false confidence and weird bugs anyhow, but it's good for catching the regressions you know about. I've had to use a lot of large third party libraries, and i could have easily tested against mocks but so, so many bugs came from the subtle manipulations of data in the sprawlling mess of a million lines of code that i would never be able to capture with mocks. You might be easier off writing integration tests against a known state to give you the confidence, rather than mocking out parts of the dependencies and crossing your fingers. Then again, It's often cheaper to rewrite it and suffer over if the code is broken enough or you have to rewrite most of it to fix the bugs anyhow. quote:2. Prevent outrageous resource setup. I've written mocked tests for a build tool (which is an ordeal I don't recommend getting into) where I can assume files were fetched over the network and create per-case dependency trees of packages. The alternative is setting up your own package registry, generating packages ahead of time, and running tests against them. testing should be approached end-to-end and then optimized in the middle. your mocks give you a quick feedback loop but i hope you still run the full suite. quote:Similarly, testing for specific external APIs or handling of network failures is far simpler by just having a mock representing the failure than by setting a remote service and hoping it fails the right way. You may still need tests to ensure actual calls work properly, but those aren't the same thing. Fault injection is lovely but it isn't really the same class of testing as mocking. Again going back to the "if you're faking idempotent behaviour then i guess it's cool"".
|
# ? Sep 28, 2015 05:28 |
|
JewKiller 3000 posted:row polymorphism is great poo poo, you can basically do statically enforced "duck typing" with it, and i have no idea why tef doesn't like it yes i like it a lot but guess how many programming languages advocated by static typing enthusiasts support it ? nominative subtyping is for chumps
|
# ? Sep 28, 2015 05:33 |
|
MALE SHOEGAZE posted:it's true. https://blog.codecentric.de/en/2013/08/cucumber-setup-basics/ code:
|
# ? Sep 28, 2015 05:46 |
|
i'm loving glad that ruby is dead. it's garbage and i can't believe that there are people who have suffered from stockholm syndrome so badly that they're working on rails apps in 2015. holy poo poo.
|
# ? Sep 28, 2015 05:49 |
|
MononcQc posted:I find the idea of cucumber hilariously bad. One more installment of 'plain English can be turned to code so that anyone can write this' that is bound to fail.
|
# ? Sep 28, 2015 05:52 |
|
When writing tests, try to create as little mocks as possible. Move the mocks to the outer boundaries of the system (e.g. file system, web service calls). If you make it so every class or small module mocks everything that it interacts with in your tests, you will make it difficult to change your system later and you aren't meaningfully testing the integration of the parts of your system which is extremely important.
|
# ? Sep 28, 2015 05:53 |
|
cucumber is the worst and i'm glad i talked work into dropping it.
|
# ? Sep 28, 2015 05:55 |
|
comedyblissoption posted:When writing tests, try to create as little mocks as possible. Move the mocks to the outer boundaries of the system (e.g. file system, web service calls). If you make it so every class or small module mocks everything that it interacts with in your tests, you will make it difficult to change your system later and you aren't meaningfully testing the integration of the parts of your system which is extremely important. well, yes, but that would be integration testing. if you're doing unit testing, then you're gonna need to mock.
|
# ? Sep 28, 2015 05:55 |
|
tef posted:yes i like it a lot but guess how many programming languages advocated by static typing enthusiasts support it ? nominative subtyping is for chumps it is a solution that addresses a mostly insignificant facet of the actual problem and encourages programmers to stick to bad code-design decisions here is the actual problem: i have a function, and i want to pass it values of different types that share a common interface row polymorphism helps when the types are (1) record types that (2) have real fields with (3) exactly the same names as each other and (4) exactly the same types as each other, but might have extra fields, and (5) the only common functionality the function wants to rely on is the presence of those fields, (6) which it will read out while ignoring the rest of the value constrained polymorphism via signatures / interfaces / protocols / type-classes generalizes this solution so much better than row-polymorphism that it is absolutely hilarious that people keep dicking around with it. its sole advantage is if you literally have a ton of interesting projection functions with completely different ad-hoc constraints, and guess what, you don't. meanwhile it encourages you to stick with lovely unencapsulated anonymous record types with redundant information storage in order to have the right set of fields for different row-polymorphic functions
|
# ? Sep 28, 2015 06:03 |
|
MALE SHOEGAZE posted:well, yes, but that would be integration testing. if you're doing unit testing, then you're gonna need to mock. The trick would be to write your units such as they are independent and decomposed so that rather than needing to mock their internal dependencies, you change their inputs only. Functional programmers come out of the woodworks about now and gloat about taking a data-centric approach. The holy grail there is to have a bunch of well tested (without mocks) independent components -- meaning low coupling and easier reuse -- and just assemble them together. When you test that assembled whole, that's your integration tests, and no mocking is ever needed. This is more wishful thinking than an actual plan though, but whenever you hit a mock, it's worth considering whether you're coupling components more than they need to be.
|
# ? Sep 28, 2015 06:04 |
|
tef posted:yes i like it a lot but guess how many programming languages advocated by static typing enthusiasts support it ? nominative subtyping is for chumps there are probably more, but the only one i can think of is (of course) ocaml: code:
code:
code:
code:
|
# ? Sep 28, 2015 06:11 |
|
rjmccall posted:constrained polymorphism via signatures / interfaces / protocols / type-classes generalizes this solution so much better than row-polymorphism that it is absolutely hilarious that people keep dicking around with it. good languages don't use row polymorphism as their sole source of constrained polymorphism. i agree that duck typing is a bad code-design decision, but there sure seem to be a lot of people who disagree, and it'd be nice to introduce static types to those people
|
# ? Sep 28, 2015 06:17 |
|
mocking is not that big of a deal but people seem to have a habit of overdoing it once they discover it. even if you're doing a functional approach and data is king, you're still gonna want to compose functions together where some of those functions involve making a network request or accessing storage or whatever non-deterministic thing, and you want to be able to pass those kinds of functions in as dependencies so that you can have tests that use deterministic implementations of those functions.
|
# ? Sep 28, 2015 06:28 |
|
JewKiller 3000 posted:good languages don't use row polymorphism as their sole source of constrained polymorphism. i agree that duck typing is a bad code-design decision, but there sure seem to be a lot of people who disagree, and it'd be nice to introduce static types to those people you still don't need row polymorphism, though. if you're going to add language features to appeal to duck-typers, give them implicit conformance, i.e. let the language figure out that type A satisfies all the constraints of some signature instead of making them write that explicitly. it's row polymorphism except it encourages them to recognize and name their protocols and actually gives them a path forward towards better code design, instead of encouraging them to write a bunch of code that will need to be majorly restructured if they ever want to move away from anonymous record types
|
# ? Sep 28, 2015 06:36 |
|
rjmccall posted:it is a solution that addresses a mostly insignificant facet of the actual problem and encourages programmers to stick to bad code-design decisions how many of the type classes use existential types? how many generic parameters are covariant or contravariant ? how many of the classes implement a protocol or a signature? a lot of the code that is typed is not typed in the cleanest way possible without a clean break between abstract interfaces and concrete classes. i have regularly been plagued by concrete types where interfaces ought to be. and tbh i am not going to maintain invasive upstream modifications on a third party code base when all i wanted to do was pass in a "list like object". it's not that i like row polymorphism but it is that i despise nominative subtyping. i really really like structural subtyping. i really like polymorphism. i am willing to go to treacherous lengths to achieve this, including duck typing
|
# ? Sep 28, 2015 06:59 |
|
tef posted:yes i like it a lot but guess how many programming languages advocated by static typing enthusiasts support it ? nominative subtyping is for chumps elm has row polymorphism and it seems pretty good to me idk
|
# ? Sep 28, 2015 07:58 |
|
MononcQc posted:I find the idea of cucumber hilariously bad. One more installment of 'plain English can be turned to code so that anyone can write this' that is bound to fail. A friend of mine wrote Yarn inspired by Cucumber, for testing programs where the interface is shell commands. It worked well for him, but I think the benefit wasn't the english language description of the test steps, more that it was a form of Literate programming, which produced a test suite which also served as documentation and specification. I'm hoping I can sneak tests into the next project where I have to work with Mr "testing is bad" by calling them stories.
|
# ? Sep 28, 2015 09:12 |
|
tef posted:3. tests slow down refactoring I see your method call assertions and raise you checking non-atomic call counters from different thread.
|
# ? Sep 28, 2015 16:59 |
|
Edison was a dick posted:I'm hoping I can sneak tests into the next project where I have to work with Mr "testing is bad" by calling them stories. Incidentally this is how Dynamic Programming got such a generic non-mathsy name.
|
# ? Sep 28, 2015 18:36 |
|
i use ruby every day and it's p ok i would kill for static typing, interfaces, and the death of monkey patching
|
# ? Sep 28, 2015 18:44 |
|
sometimes i read these posts about row polymorphism and go "what the gently caress is this look at these smart fellers" then i remember it's just writing a c++ thing that takes a class type as a template argument and relies on that class type to have a given function or it breaks horribly and i think remember that 99.99999999999% of thetime a well-named interface is better
|
# ? Sep 29, 2015 03:01 |
|
imagine this http://www.haskellforall.com/2012/05/scrap-your-type-classes.html plus row polymorphism. thats elm's current approach to "interfaces"
|
# ? Sep 29, 2015 04:13 |
|
Phobeste posted:sometimes i read these posts about row polymorphism and go "what the gently caress is this look at these smart fellers"
|
# ? Sep 29, 2015 05:25 |
|
basically interfaces + implicit implementation of interface members = what the gently caress are you complaining about, row polymorphailures
|
# ? Sep 29, 2015 05:29 |
|
i wrote some php today and lol @ comments that affect the code code:
|
# ? Sep 29, 2015 08:13 |
|
lol @ aspect oriented programming whats that, typo3 or something?
|
# ? Sep 29, 2015 08:43 |
|
my stepdads beer posted:i wrote some php today and lol @ comments that affect the code wish your postcontroller routed to /dev/null
|
# ? Sep 29, 2015 09:59 |
|
from pages ago b/c i don't understand any of this recent stuff about cucumbersFergus Mac Roich posted:noob question but you can just set the onClick listener or w/e for a particular view in code in the fragment as opposed to the xml, right? i'm writing my first android app and i think that's what i'm going with rather than making GBS threads up my activity with random fragment-related methods. by which i mean it totally doesn't make any loving sense at all but i bet that's probably how they made it do things. i remember seeing some idiot xamarin thing where i think there was some type of method that had like a whole different signature depending on whether it was defined in xml or code so wouldn't be surprised if android does something almost as dumb Flat Daddy posted:angualr toStrings your function at runtime, so if you minified first then it will see 'a' or w/e instead of '$http' and it won't work.
|
# ? Sep 29, 2015 10:21 |
|
my stepdads beer posted:i wrote some php today and lol @ comments that affect the code eh, symfony is one of the few php things that isn't completely clown-town. i can't really hate on it.
|
# ? Sep 29, 2015 16:30 |
|
|
# ? Jun 12, 2024 05:33 |
|
jony neuemonic posted:eh, symfony is one of the few php things that isn't completely clown-town. i can't really hate on it. is that like giving hitler due credit for the autobahns?
|
# ? Sep 29, 2015 20:48 |