bedobi
Joined 7 years ago
Joined 7 years ago
Now, my us citizen spouse and I are filing a spouse based green card application. (of course, we also filed for EA and AP)
Anything you can tell us about how long it might take, how many requests for extra documents they might ask for? (I understand you haven't seen our application, to our minds it's very thorough, like 400 pages, but yeah, in all generality)
Thank you Peter!
Kotlin, Java, basically every other language except Haskell, F# etc didn't get that memo
A monad is anything you can flatmap with
The monad of list is you flatmap a list on a list and instead of getting a list of lists, as you would if you just mapped, you get a single flattened list
The monad of Result is you flatmap many function calls (like http requests or whatever) on each other and instead of getting many results, you get a single flattened result
Most of you already know this, without necessarily even knowing what a Monad is
Monad literally just means "one thing" - you take many things, and flatmap them into one
Thanks for attending my ted talk
* Built the app (into a self contained .jar, it was a JVM shop)
* Put the app into a Ubuntu Docker image. This step was arguably unnecessary, but the same way Maven is used to isolate JVM dependencies ("it works on my machine"), the purpose of the Docker image was to isolate dependencies on the OS environment.
* Put the Docker image onto an AWS .ami that only had Docker on it, and the sole purpose of which was to run the Docker image.
* Combined the AWS .ami with an appropriately sized EC2.
* Spun up the EC2s and flipped the AWS ELBs to point to the new ones, blue green style.
The beauty of this was the stupidly simple process and complete isolation of all the apps. No cluster that ran multiple diverse CPU and memory requirement apps simultaneously. No K8s complexity. Still had all the horizontal scaling benefits etc.
I also prefer pattern matching over dynamic dispatch. But I maintain that conjuring up attributes out of thin air (which is 100% what you're doing when your function accepts one type, and then inside, conjures up another, that has additional attributes from the input!) is insane. There are so many good reasons not to want to do this I don't even know where to begin. For one, it's a huge footgun for when you add another type that inherits - the compiler will NOT force you to add new branches to cover that case, even though you may want it to. Also, such "reusable" if this then do this else do that methods when allowed to propagate through the stack means every function is no longer a function, it's actually *n functions, so ease of grokking and maintainability goes out the window. It's much better to relegate such ifs to the edges of the system (eg the http resource endpoint layer) and from there call methods that operate on what you want them to operate on, and do not require ifs.
> Inheriting from a class creates dispatch problems, and there's instance variables/fields/whatever to deal with. Never mind multiple inheritance, as that gets hairy real fast. With interfaces there is no hierarchy, and all there is is a type and a data, and you either pass them around together, you monomorphize to avoid the need to pass two pointers instead of one, or you have the data point to its type in a generic way. With class hierarchies you have to have operations to cast data up and down the hierarchy, meaning trade one dispatch table for another.
I agree with all of this. With interfaces, you get all the benefits, but none of the downsides.
the point of the example wasn't to be an idiomatic solution to that problem, but to illustrate the pointlessness of inheritance in general, and User Student Employee was the first thing that came to mind that was more "real" than the usual Animal examples
in any case, as for only having a User reference, you don't ever have only a User reference - overwhelmingly you would usually load a Student or Employee,
and each of them would have those attributes on them that characterize each of them respectively (and those attributes would not be shared - if they were, such shared attributes would go on the User object)
only those functions that truly are operating only on User would you send in each of their User objects
the problem with what you're advocating is you end up with functions like this
fun doSomething(user: User) { if (user is Student) { do this } else { do that } }
which is insaneBut most of them put the cart before the horse (deliberately design a "problem" that inheritance "solves") and don't seriously evaluate pros and cons or even consider alternatives.
Even then, some of the examples might be legitimate, and what you're referring to might be a case of one. (though I doubt there's no equally elegant and succinct way to do it without inheritance)
But none of that changes the fact that inheritance absolutely shouldn't be the default goto solution for modeling any domain it has become (and we are taught to understand it as)
or that it's exceedingly uncommon to come across situations like yours where you have 500+ shared cases of behavior and you only want to "override" 5
or that inheritance is overwhelmingly used NOT for such niche edge cases but as a default tool to model even the most trivial relationships, with zero justification or consideration
if both Student and Employee need to implement those interfaces, it's probably User that should have and implement them, not Student and Employee (and if they truly do need to have an implement them, they can simply delegate to their internal User = "no override" or provide a unique implementation = "override") (let alone that unless I'm misremembering in Kotlin interfaces can have default implementations)
eg in the contrived example I gave, any of all three of the User, Student and Employee can implement the interface (and if needed Student could simply delegate to its internal User while Employee could "override" by providing its own, different implementation)
The valuable part of Software Engineering isn't PARSING a solution into code and back again, taking into account all the idiosyncrasies and edge casey bugs of any given language chosen for the implementation. Of course that is a discrete and impressive skill, but it's no longer terribly valuable.
The valuable part of Software Engineering is "given this problem, what's an elegant, efficient, testable, scalable, maintainable, observable solution?".
Most of CS is already a solved problem, so even that is mostly a matter of assembling those solved-problem pieces together and choosing the flavor of how it's expressed. (for me, it's pure functions, for others, it might be OOP)
AIs are pretty good at that too, so it seems to me like the Software Engineers role is now to cultivate taste (what, in a perfect world, systems SHOULD look like) and balance it with pragmatism. (what does the system/business/time/resource constraints look like TODAY)