[HN Gopher] Show HN: I Wrote a Book on Java
___________________________________________________________________
Show HN: I Wrote a Book on Java
https://www.manning.com/books/data-oriented-programming-in-j...
This book is a distillation of everything I've learned about what
effective development looks like in Java (so far!). It's about how
to organize programs around data "as plain data" and the
surprisingly benefits that emerge when we do. Programs that are
built around the data they manage tend to be simpler, smaller, and
significantly easier understand. Java has changed radically over
the last several years. It has picked up all kinds of new language
features which support data oriented programming (records, pattern
matching, `with` expressions, sum and product types). However, this
is not a book about tools. No amount of studying a screw-driver
will teach you how to build a house. This book focuses on house
building. We'll pick out a plot of land, lay a foundation, and
build upon it house that can weather any storm. DoP is based
around a very simple idea, and one people have been rediscovering
since the dawn of computing, "representation is the essence of
programming." When we do a really good job of capturing the data in
our domain, the rest of the system tends to fall into place in a
way which can feel like it's writing itself. That's my elevator
pitch! The book is currently in early access. I hope you check it
out. I'd love to hear your feedback. You can get 50% off (thru
October 9th) with code `mlkiehl`
https://www.manning.com/books/data-oriented-programming-in-j...
Author : goostavos
Score : 564 points
Date : 2024-09-23 18:56 UTC (1 days ago)
| raju wrote:
| Let me start by saying (as someone who has written a few
| technical books of his own)--Congratulations!
|
| I am sure you (assuming this is your first book) are learning
| that this is a labor of love, and I wish you the very best in
| this endeavor. You should be proud!
|
| I was exposed to "data oriented programming" thanks to Clojure--
| wherein maps/sets are the constructs used to pass data (as plain
| data) around, with simple functions that work with the data, as
| opposed to the traditional OO (hello ORM) that mangles data to
| fit some weird hierarchy.
|
| Java's recent innovations certainly make this a lot easier, and I
| am glad someone is looking at propagating a much needed message.
|
| I will take a look at the book, but I wish you the very best.
| mrbonner wrote:
| I am also very interested in how this work in practice. With
| OOP at least you know the shape of your data structure as
| opposed to the hash map as a mere container type.
| akavi wrote:
| You can get strongly typed "shaped" data without objects[0],
| even in Java: Records[1].
|
| ~Unfortunately, I believe they're mutable (and cannot be made
| immutable).~ Edit: I was wrong, they're immutable.
|
| [0]: I'm using "object" to mean "data bound to methods",
| since the concept of aggregate data in general long pre-date
| OOP (eg, C's structs)
|
| [1]: https://docs.oracle.com/en/java/javase/17/language/recor
| ds.h...
| bedatadriven wrote:
| A record's fields are final, so records are immutable
| (though they can include immutable pointers to mutable
| objects)
| taftster wrote:
| Java Records are immutable (by the most common definition).
| They don't have any means to update the record (via
| setters, etc.) after construction. That doesn't mean, for
| example, you can't store a reference to a mutable type (for
| example, a List or Map) in your record.
|
| The frustration I have with Records is there is no good way
| to prevent direct construction of them. That is, the
| constructor is public, which prevents an easy way of
| enforcing an invariant during construction.
|
| For example, let's say that you have a record with a Date
| type. There's no good way to prevent a user from creating
| the record with an invalid date, one that is out of a
| needed date range. Or maybe enforcing a field cannot be
| null or some combination of fields must meet requirements
| as a group.
|
| The benefit I get from the classic Builder pattern is
| defeated with Records. I can't enforce checking of my
| fields before the construction of the record object itself.
| Presumably I would need to verify the object after
| construction, which is unfortunate.
| akavi wrote:
| Can you make the Record class private to a module, and
| only export a static function that constructs them?
|
| (I know very little about Java)
| kaba0 wrote:
| To a degree, yes, that's possible. But leaking a private
| type over module boundaries is bad form, so a better
| (though possibly over engineered solution) would be to
| have a separate public interface, implemented by the
| private record type, and the static function would have
| that interface as return type.
| enugu wrote:
| Why is it bad form to expose a record type only via
| custom functions and not its field accessors? Isn't this
| just like exposing a more usual object with its public
| functions and private functions remain inaccessible?
| vips7L wrote:
| You can enforce some invariants during construction:
| record Point(int x, int y) { Point {
| if (x < 0) throw new IllegalArgumentException()
| } }
|
| or if you want to assert something is not null:
| record Person(String name) { Person {
| requireNonNull(name); } }
| nogridbag wrote:
| I think records will be much more useful if
| https://openjdk.org/jeps/468 gets out of preview.
| snmx999 wrote:
| You can create dedicated, already verified objects to
| pass on to your record. E.g. AllowedDate (extends Date).
| tpmoney wrote:
| As mentioned by the other commenters, you should be able
| to run any validations or transformations on the data
| that you want in the canonical constructor, including re-
| assigning values (for example we've done defaults with
| `foo != null ? foo : new DefaultFoo()`). The only thing I
| think you can't do with a record is make the canonical
| constructor private and force users of your type to call
| factory methods that can return null instead of throwing
| an exception. You can provide those factory methods, but
| anyone can still call the constructor, so you have to do
| your hard checks in the constructor. On the other hand,
| no matter how many alternate constructors or factory
| methods you make, you're also guaranteed that every one
| of them eventually has to call the canonical constructor,
| so you don't need to spread your validation around
| either.
| elric wrote:
| > There's no good way to prevent a user from creating the
| record with an invalid date
|
| That is factually incorrect.
|
| You can do all of that validation in a record
| constructor, much like in a normal Java class
| constructor. There's a difference in syntax: you don't
| need to repeat the constructor arguments in parantheses,
| and don't have to perform the assignments yourself. These
| are tailored specifically for easy validation.
| geophile wrote:
| I am an OOP programmer going back to the late 80s (including
| the cfront days of C++), and a serious user of Python since
| 2007.
|
| In Python, I sometimes try data-oriented programming, using
| lists and dicts to structure data. And I find that it does
| not work well. Once I get two or more levels of nesting, I
| find it far too easy to get confused about which level I'm
| on, which is not helped by Python's lack of strong typing. In
| these situations, I often introduce objects that wrap the map
| or dict, and have methods that make sense for that level. In
| other words, the objects can be viewed as providing clear
| documentation for the whole nested structure, and how it can
| be navigated.
| goostavos wrote:
| >Once I get two or more levels of nesting, I find it far
| too easy to get confused about which level I'm on
|
| Author here, I agree with you. I have the working memory of
| a small pigeon.
|
| The flavor of data orientation we cover in the book
| leverages strongly typed representations of data (as
| opposed to using hash maps everywhere). So you'll always
| know what's shape it's in (and the compiler enforces it!).
| We spend a lot of time exploring the role that the type
| system can play in our programming and how we represent
| data.
| joshlemer wrote:
| Given the strongly typed flavour of data oriented
| programming, I wonder if you have any thoughts on the
| "proliferation of types" problem. How to avoid,
| especially in a nominally typed language like Java, an
| explosion of aggregate types for every context where
| there may be a slight change in what fields are present,
| what their types are, and which ones are optional.
| Basically, Rich Hickey's Maybe Not talk.
| record Make(makeId, name) record Model(modelId,
| name) record Car(make, model, year)
| record Car(makeId, modelId, year) record
| Car(make, model) record Car(makeId, modelId)
| record Car(make, year) record Car(makeId, year)
| record Car(make, model, year, colour) record
| Car(makeId, modelId, year, colour) record
| Car(year, colour) ....
| nicoty wrote:
| I'm not familiar with Java. Does it have no notion of
| structural types at all? If it does, maybe you could wrap
| those fields in `Car` with `Maybe`/`Option` (I'm not sure
| what the equivalent is in Java) so you get something like
| `Car(Maybe Make, Maybe Model, Maybe Year, Maybe Colour)`?
| spullara wrote:
| yes and it is called Optional (rather than Maybe)
| vips7L wrote:
| Records are structural types. Null restricted types are
| in draft: https://openjdk.org/jeps/8303099
| goostavos wrote:
| I have a long convoluted answer to this.
|
| I love that talk (and most of Rich's stuff). I consider
| myself a Clojure fanboy that got converted to the dark
| side of strong static typing.
|
| I think, to some degree, he actually answers that
| question as part of his talk (in between beating up
| nominal types). Optionality often pops up in place of
| understanding (or representing) that data has a context.
| If you model your program so that it has "15 maybe
| sheep," then... you'll have 15 "maybe sheep" you've got
| to deal with.
|
| The possible combinations of all data types _that could
| be made_ is very different from the subset that actually
| express themselves in our programs. Meaning, the actual
| "explosion" is fairly constrained in practice because
| (most) businesses can't function under combinatorial
| pressures. There's some stuff that matters, and some
| stuff that doesn't. We only have to apply typing rigor to
| the stuff that matters.
|
| Where I _do_ find type explosions tedious and annoying is
| not in expressing every possible combination, but in
| trying to express the slow accretion of information. (I
| think he talks about this in one of his talks, too).
| Invoice, then InvoiceWithCustomer, then
| InvoiceWithCustomerAndId, etc... the world that
| microservices have doomed us to representing.
|
| I don't know a good way to model that without
| intersection types or something like Rows in purescript.
| In Java, it's a pain point for sure.
| jakjak123 wrote:
| Hopefully your domain is sane enough that you can read
| nearly all the data you are going to use up front, then
| pass it on to your pure functions. Speaking from a Java
| perspective.
| 1propionyl wrote:
| My sense is that what's needed is a generalization of the
| kinds of features offered by TypeScript for mapping types
| to new types (e.g. Partial<T>) "arithmetically".
|
| For example I often really directly want to express is "T
| but minus/plus this field" with the transformations that
| attach or detach fields automated.
|
| In an ideal world I would like to define what a "base"
| domain object is shaped like, and then express the
| differences from it I care about (optionalizing, adding,
| removing, etc).
|
| For example, I might have a Widget that must always have
| an ID but when I am creating a new Widget I could just
| write "Widget - {.id}" rather than have to define an
| entire WidgetCreateDTO or some such.
| piva00 wrote:
| > For example, I might have a Widget that must always
| have an ID but when I am creating a new Widget I could
| just write "Widget - {.id}" rather than have to define an
| entire WidgetCreateDTO or some such.
|
| In this case you're preferring terseness vs a true
| representation of the meaning of the type. Assuming that
| a Widget needs an ID, having another type to express a
| Widget creation data makes sense, it's more verbose but
| it does represent the actual functioning better, you pass
| data that will be used to create a valid Widget in its
| own type (your WidgetCreationDTO), getting a Widget as a
| result of the action.
| 1propionyl wrote:
| > Assuming that a Widget needs an ID, having another type
| to express a Widget creation data makes sense, it's more
| verbose but it does represent the actual functioning
| better
|
| I agree with this logically. The problem is that the
| proliferation of such types for various use cases is
| extremely detrimental to the development process (many
| more places need to be updated) and it's all too easy for
| a change to be improperly propagated.
|
| What you're saying is correct and appropriate I think for
| mature codebases with "settled" domains and projects with
| mature testing and QA processes that are well into
| maintenance over exploration/iteration. But on the way
| there, the overhead induced by a single domain object
| whose exact definition is unstable potentially
| proliferating a dozen types is
| developmentally/procedurally toxic.
|
| To put a finer point on it: be fully explicit when rate
| of change is expected to be slow, but when rate of change
| is expected to be high favor making changes easy.
| piva00 wrote:
| > What you're saying is correct and appropriate I think
| for mature codebases with "settled" domains and projects
| with mature testing and QA processes that are well into
| maintenance over exploration/iteration. But on the way
| there, the overhead induced by a single domain object
| whose exact definition is unstable potentially
| proliferating a dozen types is
| developmentally/procedurally toxic.
|
| > To put a finer point on it: be fully explicit when rate
| of change is expected to be slow, but when rate of change
| is expected to be high favor making changes easy.
|
| I agree with the gist of it, at the same time I've worked
| in many projects which did not care about defining a
| difference between those types of data in their
| beginning, and since they naturally change fast they
| accrued a large amount of technical debt quickly. Even
| more when those projects were in dynamically typed
| languages like Python or Ruby, relying just on test cases
| to do rather big refactorings to extrincate those logical
| parts are quite cumbersome, leading to avoidance to
| refactor into proper data structures afterwards.
|
| Through experience I believe you need to strike a
| balance, if the project is in fluid motion you do need to
| care more about easiness of change until it settles but
| separating the actions (representation of a full fledged
| entity vs representation of a request/action to create
| the entity, etc.) is not a huge overhead given the
| benefits down the line (1-3 years) when the project
| matures. Balancing this is tricky though, and the main
| reason why any greenfield project requires experienced
| people to decide when flexibility should trump better
| representations or not.
| 1propionyl wrote:
| > Through experience I believe you need to strike a
| balance, if the project is in fluid motion you do need to
| care more about easiness of change until it settles but
| separating the actions (representation of a full fledged
| entity vs representation of a request/action to create
| the entity, etc.) is not a huge overhead given the
| benefits down the line (1-3 years) when the project
| matures. Balancing this is tricky though, and the main
| reason why any greenfield project requires experienced
| people to decide when flexibility should trump better
| representations or not.
|
| I am in complete agreement, and this is why experienced
| architects and project managers are so key. Effective
| software architecture has a time dimension.
|
| Someone needs to have the long term picture of how the
| architecture of the system with develop, enforce a plan
| so that the project doesn't get locked into or cut by
| early-stage decisions long term, but also doesn't suffer
| the costs of late-stage decisions early on, and manage
| the how/when of the transition process.
|
| I think we could have better tools for this. Some of them
| in libraries, but others to be effective may need to be
| in the language itself.
| glenjamin wrote:
| Do you mean in TypeScript or in another language?
|
| In TS the `Omit<T, K>` type can be used to remove stuff,
| and intersection can be used to add stuff
| geophile wrote:
| This discussion sounds like there is confusion about the
| Car abstraction.
|
| Make and model vs. makeId and modelId: Pick one. Are Make
| and Model referenced by Cars or not? There seems a slight
| risk of the Banana/Monkey/Jungle problem here, so maybe
| stick with ids, and then rely on functions that lookup
| makes and models given ids. I think it's workable either
| way.
|
| As for all the optional stuff (color, year, ...): What
| exactly is the problem? If Cars don't always have all of
| these properties then it would be foolish of Car users to
| just do myCar.colour, for example. Test for presence of
| an optional property, or use something like Optional<T>
| (which amounts to a language supported testing for
| presence). Doesn't any solution work out pretty much the
| same? When I have had this problem, I have _not_ done a
| proliferation of types (even in an inheritance hierarchy)
| -- that seems overly complicated and brittle.
| PaulHoule wrote:
| Hickey is great at trash-talking other languages. In the
| case of Car you might build a set of builders where you
| write
| Car.builder().make("Buick").model("LeSabre").build()
|
| Or in a sane world code generate a bunch of constructors.
|
| In the field of ontology (say OWL and RDF) there is a
| very different viewpoint about 'Classes' in the objects
| gain classes as they gain attributes. :Taylor_Swift is a
| :Person because she has a :birthDate, :birthPlace and
| such but was not initially a :Musician until she
| :playsInstrument, :recordedTrack, :performedConcert and
| such. Most languages have object systems like Java or C++
| where a Person can't start out as not a Musician but
| become one later like the way they can in real life.
|
| Notably in a system like the the terrible asymmetry of
| where does an attribute really belong is resolved, as in
| real life you don't have to say it is primary that Taylor
| Swift recorded the Album Fearless or that Fearless was
| recorded by Taylor Swift.
|
| It's a really fascinating question in my mind how you
| create a 'meta object facility' that puts a more powerful
| object system on your fingers in a language like Java or
| Python, for instance you can have something like
| taylorSwift.as(Musician.class)
|
| which returns something that implements the
| Musician.class interface if
| taylorSwift.isA(Musician.class)
|
| where TaylorSwift instanceof
| MetaObject.class
| romwell wrote:
| Well, that's what C++ templates were made for.
|
| White your code to work on Musicians, pass Taylor Swift
| in.
|
| If she's not a musician, your code won't compile.
| PaulHoule wrote:
| What I am talking about is more dynamic, although meta-
| objects could be made more static too.
|
| Particularly, I am not a Musician now but if I learned to
| play an instrument or performed at a concert I could
| become a Musician. This could be implemented as
| paulHoule.isA(Musician.class)
| # false
| paulHoule.as(Musician.class).playsInstruments()
| # an empty Set<Instrument> paulHoule.as(Musician.c
| lass).playsInstruments().add(trumpet)
| paulHoule.isA(Musician.class)
| # now true
|
| I really did build a very meta object facility that
| represented objects from this system
|
| https://en.wikipedia.org/wiki/Meta-Object_Facility
|
| in an RDF graph and provided an API in Python that made
| those objects look mostly Pythonic. Inheritance in MOF is
| like Java so I didn't need to use any tricks to make
| dynamic classes (possible in RDF) available.
| mhuffman wrote:
| This is interesting. It seems like a logic language (like
| Prolog) would work more naturally.
| cutler wrote:
| builder() .... build() Rich Hickey got something right.
| This is about as far from the idea behind DOP as it gets.
| Tainnor wrote:
| That's on Java, though. Many other languages such as
| Kotlin, Swift, etc. have better ways of dealing with
| this, e.g. in Kotlin Car(make = "Buick",
| model = "LeSabre")
| kentosi wrote:
| I haven't yet had the luxury to experiment with the
| latest version of Java, but this is one of the reasons
| why I wish Java introduced named parameters the say way
| kotlin and scala do.
|
| Eg: data class Make(makeId: String, name:
| String) data class Model(modelId: String, name:
| String) data class Car(make: Make, model:
| Model, year: String, ...)
|
| Now you can go ahead and order the params whichever way
| you wish so long as you're explicitly naming them:
| val v1 = Car(make = myMake1, model = myModel1, year =
| "2023", ...) val v1 = Car(model = myModel1, make =
| myMake1, year = "2023", ...)
| Ironlink wrote:
| Once withers land, I think you could approximate this by
| letting your record class have a zero argument
| constructor which sets every field to some blank value,
| and then fill the fields using `with`.
| var x = new Car() with { make = "Volvo"; year = "2023";
| };
|
| If you want the Car constructor to enforce constraints,
| you could use this pattern in a separate Builder record:
| record Car(String make, String year) { Car {
| Objects.requireNonNull(make);
| Objects.requireNonNull(year); }
| record Builder(String make, String year) {
| Builder() { this(null, null); }
| Car build() { return new Car(make, year);
| } } } var x = new Car.Builder()
| with { make = "Volvo"; year = "2023"; }.build();
|
| Obviously syntax TBD.
| Tainnor wrote:
| So much syntax to enable something that other languages
| have had for 10+ years. That's why I can't take the "Java
| is as good as Kotlin now" arguments seriously.
| javanonymous wrote:
| I think named parameters would be a great addition
|
| For now, I use Lombok's @Builder annotation. It makes it
| much easier to create and copy a record, where non-
| assigned attributes are set to default.
|
| Example: var bmw =
| Car.builder().make("BMW").build()
|
| It also has a practical toBuilder() syntax that creates a
| copy of the original record, with some attributes changed
| var other = bmw.toBuilder().year(2024).build()
| cbsmith wrote:
| That one is pretty simple. You have a Car object with
| four fields. The types of the fields are, respectively
| Optional<Make>, Optional<Model>, Optional<Year>, and
| Optional<Colour>.
|
| Hickey makes it sound worse than it is.
| chii wrote:
| so now when you have a function that takes in a Car
| object, you have no idea what fields those objects might
| have, because it's all optional! Which means the checks
| for the validity of each field end up spreading out to
| every function.
| chipdart wrote:
| > so now when you have a function that takes in a Car
| object, you have no idea what fields those objects might
| have, because it's all optional!
|
| Your types are already optional if you're adding
| constructors for each permutation of all input
| parameters.
| cbsmith wrote:
| Frankly, your contract was that you have no idea what
| fields those objects might have. I'm just fulfilling it.
| You won't have checks for validity of each field, as
| Optional is valid, but you will have to have code that
| handles Optional<> types (so things like
| foo.getModel().orElse()...), which is the requirement you
| described. That doesn't mean you'll be constantly
| checking the validity of each field.
| Tainnor wrote:
| Which is no worse than the situation in a dynamically
| typed language where every field in every object could be
| optional.
|
| Dynamic typing advocates sometimes miss that statically
| typed languages don't force you to encode every invariant
| in the type system, just those that seem important
| enough.
|
| Or, if you really want to go overboard, you could use a
| dependently typed language and write functions that only
| accept cars with a specific combination of fields not
| being empty. But that's typically not worth the
| complexity.
| chipdart wrote:
| > Given the strongly typed flavour of data oriented
| programming, I wonder if you have any thoughts on the
| "proliferation of types" problem.
|
| Not a problem.
|
| You're just making your life needlessly hard and blaming
| Java for the problems you're creating for yourself.
|
| This represents, coincidentally, the bulk of the problems
| pinned on Java.
|
| Everywhere else the problem you described is a variant of
| an anti-pattern and code smell widely known as
| telescoping constructor pattern.
|
| The problems caused by telescoping constructors have a
| bunch of known cures:
|
| - builder pattern (Lombok supports this, by the way),
|
| - the parameter object pattern (builder pattern's poor
| cousin)
|
| - semantically-appropriate factory methods.
|
| The whole reason behind domain models taking the center
| stage when developing a software project is that you
| build your whole project around a small set of types with
| the necessary and sufficient expressiveness to represent
| your problem domain.
|
| Also, "explosion of aggregate types" can only become a
| problem if for some reason you don't introduce support
| for type conversion when introducing specialized types.
| kaba0 wrote:
| I have thoroughly enjoyed that Hickey talk, but I think
| he has a very _system_ -oriented view/take - which is
| very important and shows his experience - but it is also
| common to have control over the whole universe for our
| program.
|
| In the interconnected system view, data schemas can
| change without notice, and the program should be
| backwards _and_ forwards compatible to a reasonable
| degree to avoid being brittle.
|
| This is not a problem when we control the whole universe.
|
| I find that Haskell-esque type systems (strongly typed
| with frequent use of algebraic data types to represent
| _every possible state in _that_ universe_ ) work better
| for the latter, but are not the best fit for the former,
| and they often have to add some escape hatches at the
| boundaries.
|
| Java itself is in a weird cross of this two - it has a
| reasonably strong type system nowadays, but it's also a
| very dynamic runtime where one can easily create their
| own class at runtime and load it, reflect on it, etc.
|
| So all in all -- are you making that Car as part of your
| universe where you control everything, and it won't
| change in unexpected ways? Make a record, potentially
| with nullable/Optional/Maybe types for the fields, if
| that makes sense.
|
| If it represents some outside data that you don't
| control, then you might only care about a subset of the
| fields: create a record type for that subset and use a
| converter from e.g. json to that record type, and the
| converter will save you from new fields. If everything is
| important then your best bet is basically what
| Clojure/JSONObject/etc do, just have a String-keyed map.
|
| (Note: structural types can help here, and I believe
| OCaml has row polymorphism?)
| cutler wrote:
| There's always clojure.spec.
| FpUser wrote:
| >"In these situations, I often introduce objects that wrap
| the map or dict, and have methods that make sense for that
| level."
|
| I've been doing the same thing since the end of the 80s as
| well starting with Turbo/Borland Pascal, C++, and later any
| other language that supports OOP.
| sodapopcan wrote:
| Python's not really built for that AFAIK, though. In
| languages built for it, you can type your
| dicts/hashes/maps/whatever and its easier to see what they
| are/know where the functions that operate on them live. I'm
| most familiar with Elixir which has structs which are
| simply specialized map (analogous to dict in Python) where
| their "type" is the name of the module they belong to.
| There can only be one struct per module, In this sense is
| easy to know exactly where its functions live and is
| _almost_ like a class with the _very_ key difference that
| modules are not stateful.
| cbsmith wrote:
| > In languages built for it, you can type your
| dicts/hashes/maps/whatever and its easier to see what
| they are/know where the functions that operate on them
| live.
|
| I think I must be misunderstanding what you mean by that,
| because I can very much do that in Python.
| sodapopcan wrote:
| I think I misunderstand OP's problem then.
| cbsmith wrote:
| Their problem stems from the scenario where you don't
| type them. You just leave them as generic lists & dicts.
| sodapopcan wrote:
| That's what I thought. I obviously don't know Python well
| enough and didn't know you can name dicts (like, beyond
| setting them to a variable). I guess you can export from
| a module so they are prefixed! Didn't think of that one
| earlier.
| cbsmith wrote:
| Python classes are basically dictionaries that have a
| distinct type bound to them. Alternatively you can
| subclass from dictionary to give yourself a distinct type
| but still be a dictionary. Slotted classes are basically
| named tuples (and of course, Python has actual named
| tuples and dataclasses), so there's a lot of ways to
| "tag" a collection with a specific type in mind.
| sodapopcan wrote:
| A typed dict is more like what I mean. Obviously I know
| about classes as I'm no stranger to OO.
| maleldil wrote:
| I'm not sure what you mean by naming dicts, but Python
| has TypedDict, where you can define the names and types
| of specific keys. They only exist for type checking and
| behave exactly as a normal dict at runtime.
|
| In modern typed Python, you can instead use dataclasses,
| NamedTuples (both in the standard library), attrs or
| Pydantic (both third-party) to represent structs/records,
| the latter also providing validation. Still, TypedDicts
| are helpful when interfacing with older code that uses
| dicts for heterogeneous data.
|
| My main gripe with them is that different TypedDicts are
| not compatible with each other. For example, it would be
| very helpful if a dict with x:str and y:str fields were
| considered superclasses of dicts with x:str, y:str and
| z:str like they are in TypeScript, but they aren't. They
| are considered different types, limiting their usability
| in some contexts.
|
| When using homogenous dicts, you can still use dict[str,
| T], and T can be Any if you don't want to type the whole
| thing. You can use any hashable type instead of str for
| keys. I often do that when reading JSON from dynamically
| typed dict[str, Any] to dataclasses.
| sodapopcan wrote:
| Awesome, thanks for the clarification.
| cbsmith wrote:
| class X(TypedDict): x: str class
| Y(TypedDict): y: str class
| XYZ(X, Y): z: str
|
| That should get you the class/superclass relationship
| that you want, no?
| maleldil wrote:
| That needs to be explicit for any interacting types. You
| must define separate classes and explicitly define their
| hierarchy. This is fine if you control all the types, but
| it breaks down quickly. The best example is having two
| TypedDicts with the same members; in Python, you cannot
| use one instead of the other. from
| typing import TypedDict class A(TypedDict):
| a: int b: str class
| B(TypedDict): a: int b: str
| def f(a: A) -> None: pass b = B(a=1, b='b')
| f(B) # mypy error: Argument 1 to "f" has incompatible
| type "type[B]"; expected "A" [arg-type]
|
| On the other hand, this is legal in Typescript:
| interface A { a: number; b: string;
| } interface B { a: number;
| b: string; } function f(a: A) {}
| const b: B = {a: 1, b: 'b'}; f(b);
|
| This is most useful when A has a subset of B's
| attributes, like this (which also doesn't work in
| Python): interface A { a:
| number; } interface B { a:
| number; b: string; }
| function f(a: A) {} const b: B = {a: 1, b:
| 'b'}; f(b);
| cbsmith wrote:
| That seems a lot like duck typing to me.
| mejutoco wrote:
| I recommend you use pydantic for type annotations.
| Alternatively, dataclasses. Then you pair it with
| typeguards @typechecked annotation and the types will be
| checked at runtime for each method/function. You can use
| mypy to check it at "compile time".
|
| Having clear data types without oop is possible, even in
| python.
| js2 wrote:
| > Python's lack of strong typing
|
| I see people conflate strong/weak and static/dynamic quite
| often. Python is strong[1]/dynamic, with optional static
| typing through annotations and a type checker (mypy,
| pyright, etc).
|
| Perhaps the easiest way to add static types to data is with
| pydantic. Here's an example of using pydantic to type-check
| data provided via an external yaml configuration file:
|
| https://news.ycombinator.com/item?id=41508243
|
| [1] strong/weak are not strictly defined, as compared to
| dynamic/static, but Python is absolutely on the strong end
| of the scale. You'll get a runtime TypeError if you try to
| add a number to a string, for example, compared to say
| JavaScript which will happily provide a typically
| meaningless "wat?"-style result.
| thelastparadise wrote:
| You're being pydantic =)
| jstimpfle wrote:
| In some significant ways, it's not strong at all. It's
| stronger than Javascript but it's difficult not to be.
| Python is a duck typing language for the most part.
| js2 wrote:
| Duck typing is an aspect of it being dynamically typed,
| not whether it is strong/weak. But strong/weak is not
| formally defined, so if duck typing disqualifies it for
| you, so be it.
|
| https://langdev.stackexchange.com/questions/3741/how-are-
| str...
| cbsmith wrote:
| I always think of Python as having "fairly strong"
| typing, because you can override the type of objects by
| just assigning to __class__.
| fire_lake wrote:
| The Python ecosystem is not built around types.
|
| For example, you will find functions where the runtime
| value of parameters will change the return type (e.g. you
| get a list of things instead of one thing). So unless we
| want to throw out huge amounts of Python libraries (and
| the libraries are absolutely the best thing Python has
| going for it) then we have to accept that it's not a very
| good statically type language experience.
|
| The JS community on the other hand had adopted TypeScript
| very widely. JS libraries are often designed with typing
| in mind, so despite being weakly typed, the static type
| experience is actually very good.
| senand wrote:
| I don't disagree. However, often, when I use a library, I
| use it within a small function that I control, which I
| can then type again. Of course, if libraries change e.g.
| the type they return over time (which they shouldn't also
| according to Rich), you often only notice if you have a
| test (which you should have anyway).
|
| Moreover, for many libraries there are types- libraries
| that add types to their interface, and more and more
| libraries have types to begin with.
|
| Anyway just wanted to share that for me at least it's in
| practice not so bad as you make it sound if you follow
| some good processes.
| zahlman wrote:
| >For example, you will find functions where the runtime
| value of parameters will change the return type (e.g. you
| get a list of things instead of one thing).
|
| I have long argued that such interfaces are doing it
| wrong. That's what "Special cases aren't special enough
| to break the rules." in the Zen is supposed to warn
| about, to my understanding.
| js2 wrote:
| YMMV. I have over two decades of experience with Python
| and about a decade with JS though it's all backend work.
| I use both in my day job, but write in Python more
| frequently. I've found the transition to Python static
| typing much more seamless and easier to adopt than TS.
|
| Amusingly, I can't call any time where I'd had to deal
| with differently typed return values in Python, but just
| recently had to fix some legacy JS code that was doing
| that (a function that was returning null, scalar, or
| array depending upon how many values it got in response
| to a SQL query).
|
| $0.02.
| lelanthran wrote:
| > You'll get a runtime TypeError if you try to add a
| number to a string, for example,
|
| A popular but nonsensical myth: $ cat
| t.py def foo(myval): return myval * 12
| print (foo("a")) $ python3 t.py
| aaaaaaaaaaaa
|
| In real-world usage, Python's "typing" is about as
| helpful as Javascript's "typing". Plain old C has
| stronger typing guarantees than Python/PHP/etc.
| zahlman wrote:
| Defining an operation between two different types is not
| at all the same thing as enabling implicit conversions.
| Notice for example that "1" * 2 gives "11", and not "2"
| nor 2. Interpreting multiplication of a string by an
| integer as "repeat the string that many times" doesn't
| require any kind of conversion (the integer is simply a
| counter for a repeated concatenation process).
| Interpreting addition as "append the base-10
| representation of the integer" certainly does. (Consider:
| _why base 10_?)
|
| You have a point that strong vs weak typing is not a
| binary and that different languages can enable a varying
| amount of implicit conversions in whatever context (not
| to mention reinterpretation of the underlying memory).
| But from ~20 years of experience, Python's type system is
| _nothing like_ JavaScript 's - and it's definitely
| helpful to those who understand it and don't fight
| against it.
|
| In my experience it's typically people from languages
| like Haskell that can't see the difference.
| Tainnor wrote:
| that's just operator overloading and it exists in many
| statically typed languages too
| ederamen wrote:
| Use Data Classes
| cbsmith wrote:
| Living this dream in Python right now (inherited a code
| base that used nasty nesting of lists & dicts). You don't
| strictly need to do OOP to solve the problem, but it really
| does help to have a data model. Using dataclasses to map
| out the data structures makes the code so much more
| readible, and the support for type hints in Python is good
| enough that you can even debug problems with the type
| system.
| chipdart wrote:
| > (...) by Python's lack of strong typing. In these
| situations, I often (...)
|
| Python does support strong typing, albeit optional, with
| type annotations and tools like mypy.
|
| If a problem is caused by the lack of strong typing, why
| not use strong typing?
| baq wrote:
| static.
|
| python was always strongly typed: you could not do 2 +
| '3', ever. nowadays mypy/pyright will tell you that
| before runtime, hence static.
| chipdart wrote:
| I stand corrected.
| ninetyninenine wrote:
| Python now has type hints which can be used with an
| external type checker in the IDE. You'd probably type it
| with a class.
| clepto wrote:
| I see a lot of people mentioning Pydantic here, but you
| should take a look into TypedDict. It provides a type
| structure ontop of a plain dictionary, and sounds like
| exactly what you'd want, and is a built-in that you don't
| need a dependency for.
|
| Mypy for example can also see the types of the dictionary
| are supposed to be when you use it just like a normal
| dictionary.
| kccqzy wrote:
| Clojure has spec. That allows you to know a specification of
| what the data structure contains.
| davedx wrote:
| With TypeScript you have types to tell you the shape of your
| data.
| goostavos wrote:
| Thanks for the kind words :)
|
| >learning that this is a labor of love
|
| I underestimated both the amount of labor and the amount of
| love that would be involved. There were more than a few "throw
| everything out and start over" events along the way to this
| milestone.
|
| Clojure definitely had a huge impact on how I think about
| software. Similarly, Haskell and Idris have rearranged my
| brain. However, I still let Java be Java. The humble object is
| really tough to beat for managing many kinds of runtime
| concerns. The book advocates for strongly typed data and
| leveraging the type system as a tool for thinking.
|
| >Java's recent innovations certainly make this a lot easier
|
| Yeah, it's an exciting time! Java has evolved so much.
| Algebraic types, pattern matching, `with` expressions -- all
| kinds of goodies for dealing with data.
| jwr wrote:
| > Clojure definitely had a huge impact on how I think about
| software
|
| I could be called a "Clojure programmer", because I make a
| living from an app written Clojure and ClojureScript. While I
| always appreciated the incredible JVM, I always looked at
| Java the language with disgust and contempt, interfacing with
| it only as was necessary, but recent work on Java makes it
| much more attractive. I was impressed by the functional
| interfaces, modern design with mostly static methods, JSR-310
| (date and time) is absolutely great -- overall, Java has
| improved a _lot_ over the years.
|
| It has come to the point where I _gasp_ might consider
| writing some Java code :-)
| greyskull wrote:
| Congratulations!
|
| I see that the book is incomplete. I didn't know that early
| access for books was a thing, very neat. It might be pertinent to
| note in your post that it's still being written, with an
| estimated release window of Spring 2025.
|
| I'm very much a "consume it when it's ready" person, so I'll keep
| this on my watch list.
| speerer wrote:
| I wonder whether it's the editing which is still in progress,
| or also the writing? The publication date seems very close if
| it's still being written.
|
| (edit-clarity)
| goostavos wrote:
| Writing is still in progress :)
|
| No firm date for the final publication yet.
| blorenz wrote:
| Congrats and keep going! I ultimately failed at mine because I
| didn't keep disciplined focus on it when life got in the way. It
| was many lessons learnt.
|
| https://www.amazon.com/Hands-Django-Beyond-Brandon-2016-03-2...
| burningChrome wrote:
| Congrats on your accomplishments!
|
| I had two friends who both wrote separate books on JS. One early
| book on Angular and the other was about jQuery. Both had a hard
| time with the critical reviews they received on Amazon and it
| really dissuaded them from doing any more technical writing.
|
| I love your approach and hope you keep writing and don't let the
| trolls get to you! Our industry needs more people who have this
| "soup to nuts" approach and take into account how nearly every
| language has changed dramatically over time.
|
| Again, congrats and keep writing.
| mands wrote:
| Technical Editor: Brian Goetz - you have my attention...
| goostavos wrote:
| It has been awesome working with him.
|
| There are few things as intimidating as having the Java
| language architect review your book on Java (haha). It's a
| much, much better book thanks to his involvement.
| flakiness wrote:
| For people who're not aware: "Brian Goetz is a Java Language
| Architect at Oracle." (from the linked page.)
| santiagobasulto wrote:
| And a great technical writer. His Java Concurrency book was a
| Bible back in the day (idk if still relevant).
| WoodenChair wrote:
| Manning let me conduct an interview with Brian a few years ago
| for my book with them. Here is the transcript:
| https://freecontent.manning.com/interview-with-brian-goetz/
|
| He was very generous with his time and there are some good
| insights there for aspiring developers, as well as some info
| about the evolution of Java which may be relevant to the more
| data-oriented features that have been added in recent times.
| microflash wrote:
| After reading Brian's post[1] on data oriented programming
| years ago, I look forward for more on the subject using Java.
|
| [1]: https://www.infoq.com/articles/data-oriented-programming-
| jav...
| matsemann wrote:
| While I'm normally not a fan of appeal to authority, knowing
| this is what moves this from "will try to remember to check
| this out when I wake tomorrow" (it's 23:04 here) to "will
| definitely check out tomorrow".
|
| Also it being from Manning helps. It's difficult to find good
| books today, so easy to self publish or get reeled in by some
| paper mill that banks on people wanting to have a book on their
| resume. So have to have something to filter out signal in the
| noise.
| jhck wrote:
| Congrats on launching the early access! I'm familiar with data-
| oriented programming from Clojure and F#, and I'm interested in
| seeing how you approach it in Java, so I just picked up a copy
| (ebook). Wish you all the best on completing the book!
| lloydatkinson wrote:
| Do you have some F# examples of data orientated programming>?
| It seems to mean a lot of different things to different people.
| goostavos wrote:
| I can highly recommend excellent Domain Modeling Made
| Functional by Scott Wlaschin for an F# book that touches on a
| lot of the ideas which back data-oriented programming
| (namely, representing your domain as strongly typed data).
| TeaVMFan wrote:
| Congratulations! In case people are looking for other modern Java
| books, here's one I'm working for building modern web apps in
| Java:
|
| https://frequal.com/Flavour/book.html
|
| It describes how to make single-page apps in Java, using the
| Flavour framework. No plugins, no extensions, and 99.9% pure
| Java. Plenty of sample code and links to relevant podcast
| episodes and demos.
| mdaniel wrote:
| Ok, I'll bite: why Subversion in 2024?
| https://sourceforge.net/p/flavour/trunk/HEAD/tree/
|
| > TeaVMFan
|
| Ah, that explains a lot of the questions I had about "modern
| webapps in Java." Relevant:
| https://news.ycombinator.com/item?id=25978053 _(TeaVM: Build
| Fast, Modern Web Apps in Java; Jan 2021)_
|
| Although I would, sincerely, enjoy hearing what KotlinJS
| doesn't do that made you want to roll your own framework?
| TeaVMFan wrote:
| Flavour supports multiple JVM languages. Plus it is a
| batteries-included framework, no need to look to extensions
| to get routing, templates, EL, JAX-RS support, and more.
| topspin wrote:
| How have you dealt with the current situation in Java where
| several new and important language features are still "preview"
| and are subject to being withdrawn? The possibility that these
| features might ultimately disappear is not theoretical: String
| Templates has been removed[1] from 23 as what would have been the
| "third preview," for example.
|
| The (likely debatable) list of features in 23 that a.) remain
| preview/incubator and b.) appear relevant to a work on data
| oriented Java programming are: Primitive Types
| in Patterns, instanceof, and switch (Preview) - JEP 455
| Implicitly Declared Classes and Instance Main Methods (Third
| Preview) - JEP 477 Flexible Constructor Bodies (Second
| Preview) - JEP 482 Vector API (Eighth Incubator) - JEP
| 469 Scoped Values (Third Preview) - JEP 481
|
| [1] https://mail.openjdk.org/pipermail/amber-spec-
| experts/2024-A... "So, to be clear: there will be no string
| template feature, even with --enable-preview, in JDK 23." - Gavin
| Bierman
| goostavos wrote:
| I've thought a lot about this quite a bit. In my day to day
| life, which is a cog in the machine at $Megacorp, I regularly
| work on embarrassingly old versions of Java (hello JDK 8!). So,
| not having the latest and greatest language features is a topic
| close to my heart. As such, the book takes a very tool agnostic
| approach. If we cover something that's only available advanced
| JDKs, we also cover what to do if you don't have it.
|
| Data oriented programming is about building around the data in
| your domain. The latest tools are nice, but they're just tools.
| topspin wrote:
| I appreciate your conundrum. While it has been good to see
| Java language designers attempt to advance the language,
| they've been extremely conservative and non-committal. This
| is a problem because tooling is costly to develop and tool
| developers are forever facing the problem of whether to
| invest the work needed to integrate these language features
| when they take years to be realized, and may yet vanish.
| Likewise for authors, such as yourself.
| whartung wrote:
| I can't say I'm completely on top of the Java world, but I
| think the String Templates are one of the very few preview
| features that have been actually withdrawn and removed, right?
| Are there others?
|
| I know some drift a bit on their implementations over time, but
| have not be wholesale yanked out.
|
| Obviously the solution to this is to not rely on these preview
| functions for production code. The way to do that is to run
| production in an LTS version of Java. I don't think that's an
| extreme point of view, frankly.
|
| The new stuff is interesting and cool, and in time, it ends up
| in the LTS version.
|
| Having lived through Java 5, 6, and 8, these are halcyon times
| for Java. It's moving VERY fast, and has been for some time.
|
| Are there preview capabilities in the LTS versions? Yes, there
| are. But they're not under the LTS tent. Don't use them. The
| demarcation between the development releases and the LTS
| releases are a smart program to get features out into the
| world, and set some real lines in the sand for advancement. It
| helps keep preview items from staying in preview mode for an
| indeterminate amount of time.
|
| And the two year LTS release cycle for a notoriously
| conservative eco-system is ample.
| topspin wrote:
| > Are there others?
|
| String Literals (JEP 326) made it to preview and got pulled.
|
| > I don't think that's an extreme point of view, frankly.
|
| Can't see where I suggested otherwise. I just wondered how
| the author was handling all the "in-flight" (An OpenJDK term
| there, not mine) features that Java currently has
| outstanding.
|
| > It's moving VERY fast, and has been for some time.
|
| They've been fast at creating new preview features. Actually
| landing finalized features though? In my view they're taking
| too long. When I compare Java and Python in this respect --
| and I do as a working programmer in both on a frequent basis
| -- Java is still slow.
| perrylaj wrote:
| > When I compare Java and Python in this respect -- and I
| do as a working programmer in both on a frequent basis --
| Java is still slow.
|
| I feel this as well, but I also think it's desirable. Java
| is slower to add features because the bar is quite a bit
| higher (especially with regard to backwards-compatibility).
|
| I'd much rather have long previews and occasional removal
| of previews than have a language that becomes bloated and
| kneecapped by past rushed decisions.
|
| There's Kotlin, Scala, Groovy, etc, if you want to run on
| the JVM with languages that offer more features (and
| footguns). I find the balance OK, personally.
|
| I'd much rather them pull the `STR.` templates than push it
| forward knowing its not ergonomic in practice.
| kaba0 wrote:
| String Literals have been superseded by Text Blocks though,
| so it's only "got pulled" as a technicality, Text Blocks
| are stable parts of the language now forever. I believe
| something similar will happen with string templates.
|
| Also, Java has gotten an insane number of new, significant
| features in the last couple of years -- loom, algebraic
| data types, pattern matching, ZGC.. I don't want to
| disrespect Python, but I really don't think they have done
| anything to this degree.
| vips7L wrote:
| Unfortunately I think we're currently in a state where all
| resources are going towards project Valhalla. Everything
| seems to be on hold until they get that out the door.
| topspin wrote:
| Valhalla is badly needed as well. That effort is 10 years
| old now.
|
| 10 years.
| vips7L wrote:
| I agree its desperately needed. But we also desperately
| need investment in the language itself (not just the
| runtime).
| globular-toast wrote:
| How does DoP compare to Domain Driven Design (DDD)?
| blackqueeriroh wrote:
| Purchased! I know very little about programming still, but Java
| is a language I have dealt with and will likely continue to have
| to deal with for the rest of my career, so here we go!
| smusamashah wrote:
| The link is returning 404 for me.
| jroseattle wrote:
| Congrats on writing and completing a book! I was involved in a
| few myself long ago, when I had the time available to contribute
| to those endeavors. In a world that often measures "the juice
| being worth the squeeze", I'm not sure authoring technical
| manuals would ever meet the criteria.
|
| One of my personal photos I keep around was taken long ago in
| what was the biggest bricks/mortar bookseller. I was looking at
| the selection of books on Java available at the time. O'Reilly
| was the dominant publisher, and thus had several offerings on the
| wall. Most of the books were at least 2 inches thick. (If you
| were ever involved with writing a technical book in the early
| 2000s, you'll understand the publisher metrics at the time were
| based on the width of the spine on the shelf.)
|
| Among the many Java manuals of significant girth was a small,
| THIN book with the title "Java -- the Good Parts". :-{}
| elric wrote:
| Does it include any content related to algebraic data types?
| goostavos wrote:
| It does! Chapter 4 specifically tackles modeling with sum and
| product types. They're used all throughout the book after that.
| elric wrote:
| Nice, thanks! The website suggests that the book will be
| published next spring. I'll be sure to preorder the print
| version.
| das_keyboard wrote:
| As someone coming from gaming, somehow early-access for books
| seems weird
| dzonga wrote:
| congrats. Data Oriented Programming is cool, but you can easily
| get lost in the complexity of certain things.
|
| there's another related book from one person active in the
| Clojure ecosystem. Though the book examples are in JS.
|
| also, thank you for taking the step forward on doing your own
| small part in changing the 'AbstractFactory' thinking that's
| pervasive in the Java world.
| ExciteByte wrote:
| For anyone interested, I think this is book you're talking
| about
|
| https://www.manning.com/books/data-oriented-programming
| necovek wrote:
| First up, congrats on getting over the hump -- I struggle to
| complete a blog post, so I very much appreciate the effort it
| takes to do this!
|
| A confusing sentence I noticed in the first chapter:
|
| > ...then the only thing cost was some time, if they do it wrong,
| the cost is usually a bug.
|
| I am guessing you mean "only cost was some time" (without the
| "thing")?
|
| As for the topic, my hypothesis is slightly different -- adopting
| functional approach to programming -- even in imperative
| languages -- leads you to the best patterns (or as you put it,
| "makes it inevitable") when combined with "evolutionary"
| architecture, and DoP is certainly one of them.
|
| However, for a majority of software, in my experience, data
| "attributes" are really "leaf nodes", only to be consumed for
| display, and types do not really matter much there (eg. I don't
| mind `firstName` being a simple string). What we want to get
| right is types we do operations on, and most critically,
| relations between different data models. Accepting "evolutionary"
| principles in architecture also means that you welcome change and
| build for it, so getting any definition of data right from start
| is not an imperative.
|
| But the topic certainly seems intriguing, so I look forward to
| learning more from your book and seeing how you apply it in a
| more imperative/OO way and what language features you found
| critical to success there.
|
| Congrats again and good luck!
| necovek wrote:
| Another typo:
|
| > ...no bad states to defend again.
|
| Defend "against", I guess?
| goostavos wrote:
| Oof -- embarrassing! At least I know what I'll be thinking
| about as I try to fall asleep tonight.
|
| Thanks for pointing out the typos and wonky wording! Will
| fix!
| olpquest22 wrote:
| Congratulations! consider posting about in
| https://www.reddit.com/r/java/ it is a very active java
| community.
| goostavos wrote:
| Will do!
| neeleshs wrote:
| Congratulations! I bought it and looking forward to the completed
| book.
|
| The first chapter is pretty nice. Record types, switch statements
| and other new features will hopefully push Java programmers to
| think in terms of types more often.
| pratikshelar871 wrote:
| Unable to checkout. Keep getting an. error
| xtreme wrote:
| As someone who loves Typescript, the first chapter of your book
| deeply resonated with me. Good data representations and data
| types that encode meaning can eliminate entire classes of bugs by
| making invalid states unrepresentable, and I wish more languages
| emphasized and supported these principles.
| victor106 wrote:
| Can't wait to read this.
|
| There's another book by a similar title
|
| https://www.manning.com/books/data-oriented-programming
|
| Care to elaborate how yours is different?
| goostavos wrote:
| Sure! The core dividing line between the two books boils down
| to how they approach representing data in a program.
| Yehonathan's book advocates for immutable data stored in
| untyped data structures (for instance, Map<Object, Object>). My
| book takes the opposite approach. It advocates for building
| around immutable data that's strongly statically typed. It aims
| to capture the stuff in our domain using algebraic data
| structures.
|
| This modeling difference has pretty far reaching implications.
| They lead to very different kinds of code bases, and thus very
| different books.
|
| Here are the repos for the two books. Poking around those
| should give you a good overview for how radically two things
| both called "data-oriented" can differ :)
|
| * https://github.com/chriskiehl/Data-Oriented-Programming-
| In-J... * https://github.com/viebel/data-oriented-programming
| victor106 wrote:
| Thank you. That helps a lot
| smrtinsert wrote:
| Very much excited to read your book. I'd remember
| conversations on old Scala forums that often talked about how
| their code bases made it impossible to enter invalid states
| through strong typing. Excited to see those ideas become
| mainstream Java concepts.
| tithos81 wrote:
| Msww
|
| I Lost T
| RandyRanderson wrote:
| I now see these threads with a language in the title as kind of a
| digital (literally) version of a voluntary committal. Those
| herein are, of their own volition, taking their thoughts and
| feelings about technology X out of the Internet at large and into
| a safe place where they can do no harm. No one in threads such as
| these are going to change their mind. It's a beautiful thing.
| tpoacher wrote:
| Congratulations! I bought a copy. If I like it I might recommend
| it as further reading for the university java course I teach. :)
|
| PS. All the best with the yacht! xD
| ephaeton wrote:
| Congratulations! It's so interesting to witness how "techniques
| of the past" make a grand return in "new" programming languages
| that "gained" features from 4 to 7 decades ago to support this
| programming style. "records, pattern matching, `with`
| expressions, sum and product types" - in my upbringing, this
| stuff is decidedly "old-school FP". People going through their
| learning curve 30 years later than I have will see what I had
| learned as "dead, possibly failed-forever FP ideas" as the "we
| tried a lot of stuff but this seemed to be the best way to do it
| after all" of their time.
| anthk wrote:
| So Java took to up 30 years to mimic Common Lisp? Ok, CL took
| almost 20 to get a proper _non-propietary_ GUI (not LispWorks
| /Allegro) close to SWING (MCCLIM), for AWT something like LTK
| was mostly enough.
| muhehe wrote:
| Is java still popular? Though I'm not a big fan of it I wouldn't
| mind using, but I'm after somewhat recent changes in licensing
| I'm not even sure I can. I don't fully understand the changes and
| I'm afraid of oracle coming after me :).
|
| Can anyone explain current caveats and/or limitations with
| current licensing?
| anta40 wrote:
| Perhaps, but probably don't attract many users like it used to
| be. For backend, some switched to Go. And on Android, some
| already switched to Kotlin.
| kaba0 wrote:
| Java is more open than ever. Those random "scary" bullshit
| posts appear here and there but -- OpenJDK is the standard
| reference implementation, and it has the same license as the
| Linux kernel. Different vendors give you _builds_ of this same
| source, with some patches here and there, and they might
| provide support for their versions. One of these vendors is
| Oracle, who gives away the _freemium_ OracleJDK. The latest LTS
| release is free to use _with support_ , until the next one
| comes along, plus one year. But you would read more about
| different support services if you would need that - the same
| stuff is available for linux. In general, you can use any of
| these builds interchangeably, it doesn't really matter. Like,
| intellij will offer you to download basically any of them.
|
| So yeah, Java is insanely popular (top 3 language, among JS and
| Python, only their orders change depending on sane metrics (not
| you tiobe)), and is completely free with multiple vendors.
| Also, it's pretty bullshit to consider Oracle any worse than
| other companies - they are the ones who completely opensourced
| OpenJDK and are responsible for 95+% of all the commits.
| munksbeer wrote:
| >Can anyone explain current caveats and/or limitations with
| current licensing?
|
| You can pretty much ignore the FUD posts about Java licensing.
| There are long winded replies to why it is FUD, but the short
| answer is it is trivially not a problem. It only applies if you
| use the Oracle JDK and want a certain type of support. Most of
| the world doesn't, instead using one of the other free JDKs.
|
| Java is *not* popular in the reddit, HN, etc memesphere. In the
| real world it remains incredibly popular and a huge number of
| organisations continue to pick it as their language of choice
| for back-end development.
| BlindEyeHalo wrote:
| Java has a huge legacy code bases that depend on it but for new
| stuff Kotlin is probably the better choice. It is fully
| compatible with Java, which means you can add Java libraries
| and import them in your Kotlin code and use, inherit, overwrite
| functions and classes but also gives all the features of a nice
| modern language. I haven't used it for a serious project but it
| felt great from what I saw so far.
|
| Android switched to it as the default as well.
| mightyham wrote:
| Kotlin has a lot of really nice language features and it's
| Java interop is a big sell, but after digging into the
| details I'm pretty pessimistic about it's long term success
| for a few reasons.
|
| They seem to be attempting to move away from the JVM,
| preferring it's own multiplatform native compilation which is
| significantly less battle tested and, last I checked, still
| suffers from serious performance issues. This is a shame too
| because Oracle has put a lot into the development of GraalVM,
| which is a great solution for native compilation of JVM
| languages, but Kotlin still wants to tread it's own path for
| some reason. It creates a weird fracture in the ecosystem
| where some libraries only support either multiplatform or the
| JVM, and I'm pretty sure Java can't even be used in
| multiplatform projects.
|
| Another big issue is that idiomatic Java code can often feel
| clumsy to use from Kotlin: for instance Kotlin function types
| don't map nicely to functional interfaces and the syntax for
| AutoClosable/try-with-resource statements is awkward. I can
| only see this getting worse in the future, as Java continues
| to develop new features and standard library APIs that are
| designed FOR JAVA. An example of this already happening is
| Java's in preview structured concurrency API. It makes heavy
| use of try-with-resource and offers duplicate but not
| necessarily compatible functionality to Kotlin's own
| coroutine API.
|
| Also build times... They have gotten better but they are
| still much worse that any plain Java project and Java build
| times are already not great.
| Tainnor wrote:
| I'm also a bit skeptical about Kotlin multiplatform, but I
| haven't seen it become an issue so far. Spring e.g. fully
| supports Kotlin (and so do tools like Gradle) and I've
| never had any issue with things not working.
|
| Calling Java code from Kotlin may not always be 100%
| idiomatic but it's still by far the best interop between
| two different languages that I've ever seen (compare that
| e.g. to Scala). The interop is more than good enough to be
| viable for a migration scenario where old stuff is written
| in Java and new things are written in Kotlin - I definitely
| wouldn't recommend keeping writing both new Java and new
| Kotlin code, though.
|
| Build times can be an issue (though hopefully improved with
| the new compiler), but incremental compilation helps
| (something that maven unfortunately sucks at, so it's
| better to use gradle). And in any case, the compiler does
| more (useful) work in Kotlin, so I think it's ok that it
| takes a bit longer.
| WuxiFingerHold wrote:
| I've read the first chapter and I like it a lot. I find myself
| way to often hiding business logic as in your first example.
| Also, showing how to use Java for DoP and combining it with other
| concepts like OOP encapsulation is very helpful IMO.
|
| Now I'm waiting for two things:
|
| 1. Manning allowing me to grab it (forgot password email
| notifications seems to hang)
|
| 2. More chapters :-) ... no, really, just let it roll. Don't
| rush.
| sidcool wrote:
| Manning is a good quality publication (unlike Packt). Congrats.
| Looking forward. Will this be available on Safari books O'Reilly
| portal?
| orsenthil wrote:
| Congratulations on writing your book.
| oveja wrote:
| Very nice! I gave you my money just for the consideration of
| people stuck in old Java versions like myself. Looking forward to
| getting the new chapters as they come!
| catzapd wrote:
| Happy to see a post on Java and a book as well.
|
| Will checkout the book.
| mattgreenrocks wrote:
| Lots of people are sleeping on modern Java, and it has had a lot
| of really nice changes, that, when put together, make it wholly
| different from what came before.
|
| One question: a lot of the Java enterprise ecosystem is based
| around entities (Hibernate and the like). Do you give guidance
| for how to work within that context? Can I use data oriented
| programming there?
___________________________________________________________________
(page generated 2024-09-24 23:01 UTC)